c               Copyright 1993 Colorado State University
c                       All Rights Reserved

      subroutine dailymoist(curday, sradKJ, soilsrad,
     &                      grass_lai, tree_lai, isdecid, isagri,
     &                      tfunc, agwfunc, bgwfunc, petdly, rpeff)

      implicit none
      include 'cflows.inc'
      include 'const.inc'
      include 'dovars.inc'
      include 'fertil.inc'
      include 'jday.inc'
      include 'npool.inc'
      include 'param.inc'
      include 'parfx.inc'
      include 'plot1.inc'
      include 'plot2.inc'
      include 'timvar.inc'
      include 't0par.inc'
      include 'seq.inc'
      include 'site.inc'
      include 'wth.inc'
      include 'wthdaily.inc'
      include 'zztim.inc'

c ... FORMAL PARAMETERS
      integer curday
      integer isdecid, isagri
      double precision sradKJ, soilsrad
      double precision grass_lai, tree_lai
      double precision tfunc
      double precision agwfunc, bgwfunc
      double precision petdly, rpeff

c ... Subroutine dailymoist
c ...
c ... This routine is called once a day: it calls
c ... the water budget routine (watrflow),
c ... the photo decomposition routine (photodecomp),
c ... the soil organic mattter decomposition routine (decomp),
c ... and the trace_gas_model.
c ...
c ... FORMAL PARAMETERS
c ... Input (used in this subroutine)
c ...   curday 		- day of the year (1..366)
c ...   isdecid 	- 1 if the system is a deciduous forest, 0 otherwise
c ...   isagri 		- 1 if the system has ever been cultivated for agriculture, 0 otherwise
c ...   sradKJ    	- amount of solar radiation (KJ/m^2/day)
c ...   soilsrad	- amount of solar radiation below the plant canopy (KJ/m^2/day)
c ...   grass_lai	- LAI of crop/grass (m^2/m^2)
c ...   tree_lai	- LAI of tree canopy (m^2/m^2)
c ... Output (for output files)
c ...   tfunc		- temperature effect on decomposition (0.0 - 1.0)
c ...   agwfunc		- above ground moisture effect on decomposition (0.0 - 1.0)
c ...   bgwfunc		- below ground moisture effect on decomposition (0.0 - 1.0)
c ...   petdly		- potential evapotranspiration that has occurred in the current day (cm H2O)
c ...
c ... LOCAL VARIABLES
c ... Temperature and Moisture
c ...   avgwfps 	- average WFPS in top 15 cm of soil (0-1)
c ...   fertN	        - amount of N fertilizer added (gN/m^2)
c ...   omadC	        - amount of C from organic matter addition (gC/m^2)
c ...   omadN	        - amount of N from organic matter addition (gN/m^2)
c ...   rprpet		- ratio of rainfall (including melt) to PET
c ...   amovdly(10)	- total net flux of water thru the bottom of each Century soil layer each day (cm H2O)
c ...   wfluxout[] 	- total net flux of water thru the bottom of each DayCent soil layer each day (cm H2O)
c ...              	  (positive is downward, negative is upward)
c ... Surface/Soil CO2 losses
c ...   CO2losUV	- CO2 loss from photodegradation of standing dead biomass and
c ...                     surface litter in the current day (gC/m^2)
c ...   CO2resp		- amount of SOIL microbial respiration in the current day (gC/m^2)
c ...   newCO2 		- modified value of CO2resp passed to the trace gas submodel (gC/m^2)
c ...   hrespCO2	- amount of microbial respiration (surface, soil, dead wood) in the current day (gC/m^2)
c ...   hresp1		- sum of ALL microbial respiration accumulators before call to decomp (gC/^2)
c ...   hresp2		- sum of ALL microbial respiration accumulators after call to decomp (gC/^2)
c ...   soilresp1	- sum of SOIL microbial respiration accumulators before call to decomp (gC/^2)
c ...   soilresp2	- sum of SOIL microbial respiration accumulators after call to decomp (gC/^2)
c ...   inorgNlch	- inorganic N leaching that has occurred in the current day (gN/m2)
c ...   orgNlch		- organic N leaching that has occurred in the current day (gN/m2)
c ...   newminrl	- mineralization that has occurred in the current day (gN/m2)
c ... Soil Leaching
c ...   fsol 		- fraction of soluble mineral in soil mineral layers (0.0 - 1.0)
c ...   frlech(MAXIEL)	- inorganic N, P, and S leaching fractions (0.0 - 1.0), used in leachdly.
c ...   texeff		- effect of soil texture (sand) in the leaching of inorganic N, P, and S
c ... Trace Gas Model Outputs
c ...   CH4		- methane consumption in the current day (gC/m^2)
c ...   Dn2oflux	- denitrification N2O flux in the current day (gN/m^2)
c ...   Dn2flux		- denitrification N2 flux in the current day (gN/m^2)
c ...   Nn2oflux	- nitrification N2O flux in the current day (gN/m^2)
c ...   NOflux		- total soil NOx flux in the current day (gN/m^2)
c ...   Note: the following 2 fluxes should increase grass and tree N storage, but for CLM linkage
c ...      esrsnk(N) will be increased instead.
c ...   NOabsorp_grass	- total NOx flux absorbed by grass in the current day (gN/m^2)
c ...   NOabsorp_tree	- total NOx flux absorbed by tree canopy in the current day (gN/m^2)
c ...   nit_amt		- amount of nitrification in the current day (gN/m^2)
c ...   dN2lyr() 	- denitrification N2 flux in the current day by soil layer (gN/m^2)
c ...   dN2Olyr()	- denitrification N2O flux in the current day by soil layer (gN/m^2)
c ... N FIXATION
c ...   atmosNdep 	- atmospheric N depostion in the current day (gN/m^2)
c ...   nonSymSoilNfix	- non-symbiotic soil N fixation in the current day (gN/m^2)
c ... C and N balance
c ...   totCstate	- total of C state variables (gC/m^2)
c ...   totNstate	- total of N state variables (gC/m^2)
c ...
c ... OTHER VARIABLES defined in include files
c ...
c ... plot1.inc
c ...   aminrl(iel)	- available mineral in the top Century soil layer (gE/m^2)
c ...   asmos(lyr)	- total water in each Century soil layer (cm_
c ...   avh2o(3)	- available water in the soil(cm)
c ...   minerl(lyr,iel) - mineral soil for Century layers (assumes nitrate + ammonium) (gE/m^2)
c ...   rwcf(lyr)	- relative water content fraction of Century layers (0.0 - 1.0)
c ...   snow		- snow water equivalent of the snowpack (cm H2O)
c ...   stream(*)       - water, inorganic stream flow, organic stream flow
c ...
c ... plot2.inc
c ...   esrsnk(iel)	- elemental source/sink (gE/m^2)
c ...
c ... npool.inc
c ...   ammonium	- ammonium-nitrogen pool, no layer structure (gN/m^2)
c ...   nitrate[]	- nitrate-nitrogen pool for DayCent soil layers (gN/m^2)
c ...   texture		- COARSE, MEDIUM, or FINE (see n2o_model.h)
c ...
c ...  dovars.inc
c ...    dofert		- true if it is time for a fertilization event
c ...    fertday	- scheduled day of year for fertilization event
c ...    doomad		- true if it is time for a organic matter addition event
c ...    omadday	- scheduled day of year for organic matter addition event
c ...
c ...  fertil.inc
c ...    nreduce
c ...
c ...  param.inc
c ...    afiel(1)	- field capacity in the top Century soil layer (volumetric fration 0.0 - 1.0)
c ...    basef
c ...    bulkd 		- avgerage soil bulk density for the soil profile (g/cm^3)
c ...    stormf
c ...    drain
c ...    nelem
c ...    pslsrb
c ...    sorpmx
c ...
c ...  parfx.inc
c ...    aneref
c ...    ntspm		- number of time steps per day (not month) for the decomp model
c ...    idef
c ...    fleach(*)	- leaching parameters
c ...    minlch
c ...    teff(*)	-
c ...
c ...  seq.inc
c ...    decsys		- 1 if no wood is present to decompose, 2 otherwise
c ...
c ...  site.inc
c ...    sand, silt, clay
c ...
c ...  t0par.inc
c ...    dt 		- time step of a month (fraction of a year)
c ...  timvar.inc
c ...    decodt		- time step for decomposition model (fraction of a year)
c ...    month
c ...
c ... wth.inc
c ...   maxt 		- long term average maximum monthly temperature (C) used in the trace gas model
c ...
c ... wthdaily.inc
c ...   avgtemp
c ...   tempmin
c ...   tempmax
c ...
c ... zztime.inc
c ...   time
c ...   time2

c ... LOCAL VARIABLES
      integer iel, kts, ntspd, ii
      integer iyr, imo, idy, ikts
      double precision cdi, amtN
      double precision fsol
      double precision texeff
      double precision frlech(MAXIEL)
      double precision fertN, omadN, omadC
      double precision inorgNlch
      double precision orgNlch
      double precision newminrl
      double precision amovdly(10)
      double precision rprpet
      double precision wfluxout(SWMAXLYR)
      double precision hresp1, hresp2
      double precision soilresp1, soilresp2
      double precision Nn2oflux, Dn2oflux, Dn2flux, NOflux
      double precision NOabsorp_grass, NOabsorp_tree
      double precision avgwfps
      double precision CH4, nit_amt
      double precision CO2losUV
      double precision CO2resp
      double precision newCO2
      double precision hrespCO2
      double precision dN2lyr(SWMAXLYR), dN2Olyr(SWMAXLYR)
      double precision atmosNdep, nonSymSoilNfix
      double precision NgasFlux
      double precision totCstate, totNstate
      double precision t1, t2, timeincrmt
      character subname*10
      integer experiment

c ... FUNCTION DECLARATIONS
      double precision anerob, fsfunc
      external anerob, fsfunc

      subname = 'dailymoist'

c ... experiment = 1, 2, 3 for litter experiments.  Set to 0 for normal execution.
c     0 = normal DayCent execution
c         compute atmospheric N dep and non-symbiotic N fixation
c ... For all non-zero experiments, set pH = 7, soilsrad = 0
c     No atmospheric N dep or non-sybiotic N fixation
c     1 = anerob = 1.0
c     2 = read cdi file instead of calculating defac
c         Reset minerl(*,*) and aminrl(*) to values specified in the site.100 file
c         Don't run tracegas model
c         anerob = 1.0
c     3 =

      experiment = 2

      totCstate = 0
      omadC = 0
      CO2resp = 0
      CO2losUV = 0
      CH4 = 0
      totNstate = 0
      fertN = 0
      omadN = 0
      orgNlch = 0
      inorgNlch = 0
      Nn2oflux = 0
      Dn2oflux = 0
      Dn2flux = 0
      NOflux = 0
      NOabsorp_grass = 0
      NOabsorp_tree = 0
      atmosNdep = 0
      nonSymSoilNfix = 0

      call cbalance(time, curday, omadC, hrespCO2, CO2losUV,
     &              CH4, totCstate)
      call nbalance(time, curday, omadN, fertN,
     &              orgNlch, inorgNlch,
     &              NOflux, Nn2oflux, Dn2oflux, Dn2flux,
     &              NOabsorp_grass, NOabsorp_tree,
     &              atmosNdep, nonSymSoilNfix, totNstate)

      decodt = dt/dble((dysimo(month)*ntspm))
c ... daily timestep (t1) has 24 * 60 minutes, the new timestep (t2) has 30 minutes
      t1 = 24 * 60
      t2 = 30
      ntspd = ntspm * 48
c ... decomposition time increment as a fraction of a year (48 decomposition timesteps per day)
      timeincrmt = 1.0 / (365.0 * 48.0)

      if (experiment .ne. 0) then
        soilsrad = 0
        ph = 7.0
      endif

      newminrl = 0.0

c ... Initialize output variables that are tracking the daily carbon
c ... flows due to decomposition (cflows.inc).
      metc1tosom11  = 0.0
      metc2tosom12  = 0.0
      struc1tosom11 = 0.0
      struc1tosom21 = 0.0
      struc2tosom12 = 0.0
      struc2tosom22 = 0.0
      som11tosom21  = 0.0
      som12tosom22  = 0.0
      som12tosom3   = 0.0
      som21tosom11  = 0.0
      som21tosom22  = 0.0
      som22tosom12  = 0.0
      som22tosom3   = 0.0
      som3tosom12   = 0.0
      wood1tosom11  = 0.0
      wood1tosom21  = 0.0
      wood2tosom11  = 0.0
      wood2tosom21  = 0.0
      wood3tosom12  = 0.0
      wood3tosom22  = 0.0

c ... Atmospheric N deposition and non-symbiotic soil N fixation
      if (experiment .eq. 0) then
        call nfixday(ppt(curday), atmosNdep, nonSymSoilNfix)
      endif

c ... Organic matter addition
      if (doomad .and. (omadday .eq. curday)) then
        call addomad(omadC, omadN)
        write(*,*) 'DOOMAD: ', time, curday, omadC, omadN
        doomad = .FALSE.
      endif

c.... Add plant litter
c     call addlit()

c ... Compute frlech, the leaching fraction.
      texeff = fleach(1) + fleach(2) * sand
      do 50 iel = 1, nelem
        if (iel .eq. P) then
          fsol = fsfunc(minerl(SRFC,P), pslsrb, sorpmx)
        else
          fsol = 1.0
        endif
        frlech(iel) = texeff * fleach(iel+2) * fsol
50    continue

c ... Fertilization option
      if (dofert .and. curday .eq. fertday) then
        call addfert(nelem, month, fertN)
      endif

      call watrflow(nlayer,
     &              avgtemp(curday), tempmin(curday), tempmax(curday),
     &              ppt(curday), petdly,
     &              wfluxout, amovdly, rwcf, asmos, avh2o, rprpet)

c ... Calculate the effect impact of anerobic conditions on decomposition
      anerb = anerob(aneref,drain,rprpet,petdly,experiment)

c ... Combined effects of temperature and moisture on decomposition
      if (experiment .ne. 2) then
        call calcdefac(texture, tfunc, agwfunc, bgwfunc,
     &                 agdefac, bgdefac, avgwfps, teff, rprpet,
     &                 idef, ppt(curday), snow, experiment)
      endif

      if (experiment .eq. 2) then
c...    Reset minerl(*,*) and aminrl(*) to values specified in the site.100 file
        do 19 iel = 1, 3
          do 17 ii = 1, nlayer
            amtN = iminerl(ii,N)-minerl(ii,N)
            minerl(ii, iel) = iminerl(ii, iel)
            if (iel .eq. N) then
              call update_npool(ii, amtN, frac_nh4_fert,
     &            frac_no3_fert, ammonium, nitrate, subname)
            endif
17        continue
          if (iel .eq. P) then
            fsol = fsfunc(minerl(1,P), pslsrb, sorpmx)
          else
            fsol = 1.0
          endif
          aminrl(iel) = minerl(1,iel) * fsol
19      continue
      endif

c ... *********************************************************************
c ... Decomposition Submodel
c ... Call decomp routines ntspd times per day

c ... Change CO2 respiration value passed to the trace gas submodel
c ... so that we are passing only soil respiration, cak - 10/22/2007
      soilresp1 = mt2c2(UNLABL) + mt2c2(LABELD) +
     &            st2c2(UNLABL) + st2c2(LABELD) +
     &            s12c2(UNLABL) + s12c2(LABELD) +
     &            s22c2(UNLABL) + s22c2(LABELD) +
     &            s3c2(UNLABL)  + s3c2(LABELD)
      hresp1 = soilresp1 +
     &            mt1c2(UNLABL) + mt1c2(LABELD) +
     &            st1c2(UNLABL) + st1c2(LABELD) +
     &            s11c2(UNLABL) + s11c2(LABELD) +
     &            s21c2(UNLABL) + s21c2(LABELD) +
     &            wd1c2(UNLABL) + wd1c2(LABELD) +
     &            wd2c2(UNLABL) + wd2c2(LABELD) +
     &            wd3c2(UNLABL) + wd3c2(LABELD)

c ... Photodecomposition of standing dead and litter
c     call photodecomp(sradKJ, soilsrad, CO2losUV)

      orgNlch = stream(6)

      do 40 kts = 1, ntspd

        if (experiment .eq. 2) then
c ........ Read defac from the cdi file, rewind the file at EOF
181        read(18, *, end=182) iyr, imo, idy, ikts, cdi
           goto 183

182        rewind(18)
           goto 181

183        continue
           agdefac = cdi
           bgdefac = cdi
           if (month .ne. imo) then
             write(*,*) 'Warning: month = ', month, ' imo = ', imo
           endif
           if (kts .ne. ikts) then
             write(*,*) 'Warning: kts = ', kts, ' ikts = ', ikts
           endif
        endif

c ... Organic matter decomposition
        call decomp(decodt,t1,t2,decsys,amovdly,newminrl,soilsrad,rpeff)

        if (nelem .ge. P) then
          call pschem(decodt, t1, t2)
        endif

c ..... Update decomposition and nitrogen fixation flows.
        call flowup(time)
        call sumcar

c ..... aminrl contains the average amount of N, P, and S available
c ..... in the top layer for the time period covered by dt/ntspd.
c ..... minerl contains the current value of mineral N, P, and S by layer.

        do 30 iel = 1, nelem
          if (iel .eq. P) then
            fsol = fsfunc(minerl(SRFC,P), pslsrb, sorpmx)
          else
            fsol = 1.0
          endif
          aminrl(iel) = (aminrl(iel) + minerl(SRFC,iel)*fsol)/2.0
30      continue
c       write(*,*) cntstep, ': minerl(1,N) = ', minerl(1,N),
c    &      'aminrl(N) = ', aminrl(N)

      cntstep = cntstep + 1
      time2 = time2 + timeincrmt

40    continue

c ... newCO2 - soil CO2 respiration value passed to the trace gas submodel
      soilresp2 = mt2c2(UNLABL) + mt2c2(LABELD) +
     &            st2c2(UNLABL) + st2c2(LABELD) +
     &            s12c2(UNLABL) + s12c2(LABELD) +
     &            s22c2(UNLABL) + s22c2(LABELD) +
     &            s3c2(UNLABL)  + s3c2(LABELD)
      hresp2 = soilresp2 +
     &            mt1c2(UNLABL) + mt1c2(LABELD) +
     &            st1c2(UNLABL) + st1c2(LABELD) +
     &            s11c2(UNLABL) + s11c2(LABELD) +
     &            s21c2(UNLABL) + s21c2(LABELD) +
     &            wd1c2(UNLABL) + wd1c2(LABELD) +
     &            wd2c2(UNLABL) + wd2c2(LABELD) +
     &            wd3c2(UNLABL) + wd3c2(LABELD)
      newCO2 = soilresp2 - soilresp1

      write(125,98) cntstep, time2, curday, month, kts,
     &              strucc(1), metabc(1), strucc(2), metabc(2),
     &              som1c(1), som2c(1), som1c(2), som2c(2),
     &              som3c, struce(1,1), metabe(1,1), struce(2,1),
     &              metabe(2,1), som1e(1,1), som2e(1,1),
     &              som1e(2,1), som2e(2,1), som3e(1), tnetmn(1),
     &              agdefac, bgdefac, somsc, somtc, newCO2
98    format(i10,',',f12.8,',',1x,3(i4,',',1x),24(f11.2,',',1x))

c ... dshresp is daily soil heterotrophic respiration, needed to calculate
c ... priming effect for the next day (see rpeff calculation in simsom.f).
      dshresp = newCO2
      hrespCO2 = hresp2 - hresp1
      if (newCO2 .le. 0.0) then
        newCO2 = 0.000001
      endif
      CO2resp = newCO2
      if (avgwfps .gt. 0.60 .and. bgwfunc .gt. 0.0) then
        newCO2 = newCO2 / bgwfunc
      endif

c ... *********************************************************************
c ... Trace Gas Model

      if (experiment .ne. 2) then
      call trace_gas_model(curday, time, newminrl, ammonium, nitrate,
     &                     texture, sand, silt, clay, afiel(1), bulkd,
     &                     maxt, ppt(curday), snow, avgwfps,
     &                     stormf, basef, frlech, stream, inorgNlch,
     &                     minlch, wfluxout, newCO2, NOflux,
     &                     Nn2oflux, Dn2oflux, Dn2flux, CH4, isdecid,
     &                     isagri, grass_lai, tree_lai, NOabsorp_grass,
     &                     NOabsorp_tree, nit_amt, nreduce,
     &                     dN2lyr, dN2Olyr)
      endif

      NgasFlux = NOflux + Nn2oflux + Dn2oflux + Dn2flux +
     &           NOabsorp_grass + NOabsorp_tree
      esrsnk(N) = esrsnk(N) + NgasFlux

c ... Update state variables and accumulators and sum carbon isotopes
      call flowup(time)
      call sumcar

c ... Now check for N balance and rebalance nh4 and no3 pools with minerl N
      minerl(1,N) = minerl(1,N) - Nn2oflux - Dn2oflux - Dn2flux -
     &                NOflux

      call bal_npool(nlayer, minerl, ammonium, nitrate, inorgNlch)

c ... *********************************************************************

c ... Organic N leaching for the day
      orgNlch = stream(6) - orgNlch

      call cbalance(time, curday, omadC, hrespCO2, CO2losUV,
     &              CH4, totCstate)
      call nbalance(time, curday, omadN, fertN,
     &              orgNlch, inorgNlch,
     &              NOflux, Nn2oflux, Dn2oflux, Dn2flux,
     &              NOabsorp_grass, NOabsorp_tree,
     &              atmosNdep, nonSymSoilNfix, totNstate)

      return
      end


        subroutine gdt2gds(igds,igdstmpl,idefnum,ideflist,kgds,
     &                     igrid,iret)
C$$$  SUBPROGRAM DOCUMENTATION BLOCK
C                .      .    .                                       .
C SUBPROGRAM:    gdt2gds
C   PRGMMR: Gilbert        ORG: W/NP11    DATE: 2003-06-17
C
C ABSTRACT: This routine converts grid information from a GRIB2
C   Grid Description Section as well as its
C   Grid Definition Template to GRIB1 GDS info.  In addition,
C   a check is made to determine if the grid is an NCEP
C   predefined grid.
C
C PROGRAM HISTORY LOG:
C 2003-06-17  Gilbert
C 2004-04-27  Gilbert - Added support for gaussian grids.
C 2007-04-16  Vuong   - Added Curvilinear Orthogonal grids.
C 2007-05-29  Vuong   - Added Rotate Lat/Lon E-grid (203)
C
C USAGE:    CALL gdt2gds(igds,igdstmpl,idefnum,ideflist,kgds,igrid,iret)
C   INPUT ARGUMENT LIST:
C     igds()   - Contains information read from the appropriate GRIB Grid
C                Definition Section 3 for the field being returned.
C                Must be dimensioned >= 5.
C                igds(1)=Source of grid definition (see Code Table 3.0)
C                igds(2)=Number of grid points in the defined grid.
C                igds(3)=Number of octets needed for each
C                            additional grid points definition.
C                            Used to define number of
C                            points in each row ( or column ) for
C                            non-regular grids.
C                            = 0, if using regular grid.
C                igds(4)=Interpretation of list for optional points
C                            definition.  (Code Table 3.11)
C                igds(5)=Grid Definition Template Number (Code Table 3.1)
C     igdstmpl() - Grid Definition Template values for GDT 3.igds(5)
C     idefnum    - The number of entries in array ideflist.
C                  i.e. number of rows ( or columns )
C                  for which optional grid points are defined.
C     ideflist() - Optional integer array containing
C                  the number of grid points contained in each row (or column).
C
C   OUTPUT ARGUMENT LIST:      (INCLUDING WORK ARRAYS)
C     kgds()   - GRIB1 GDS as described in w3fi63 format.
C     igrid    - NCEP predefined GRIB1 grid number
C                set to 255, if not NCEP grid
C     iret     - Error return value:
C                  0  = Successful
C                  1  = Unrecognized GRIB2 GDT number 3.igds(5)
C
C REMARKS: LIST CAVEATS, OTHER HELPFUL HINTS OR INFORMATION
C
C ATTRIBUTES:
C   LANGUAGE: INDICATE EXTENSIONS, COMPILER OPTIONS
C   MACHINE:  IBM SP
C
C$$$
!
        integer,intent(in) :: idefnum
        integer,intent(in) :: igds(*),igdstmpl(*),ideflist(*)
        integer,intent(out) :: kgds(*),igrid,iret

        integer :: kgds72(200),kgds71(200),idum(200),jdum(200)

        iret=0
        if (igds(5).eq.0) then       !  Lat/Lon grid
           kgds(1)=0
           kgds(2)=igdstmpl(8)            ! Ni
           kgds(3)=igdstmpl(9)            ! Nj
           kgds(4)=igdstmpl(12)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(13)/1000      ! Long of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(14),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(15)/1000      ! Lat of last grid point
           kgds(8)=igdstmpl(16)/1000      ! Long of last grid point
           kgds(9)=igdstmpl(17)/1000      ! Di
           kgds(10)=igdstmpl(18)/1000     ! Dj
           kgds(11)=igdstmpl(19)          ! Scanning mode
           kgds(12)=0
           kgds(13)=0
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
           !
           !  Process irreg grid stuff, if necessary
           !
           if ( idefnum.ne.0 ) then
              if ( igdstmpl(8).eq.-1 ) then
                 kgds(2)=65535
                 kgds(9)=65535
              endif
              if ( igdstmpl(9).eq.-1 ) then
                 kgds(3)=65535
                 kgds(10)=65535
              endif
              kgds(19)=0
              kgds(20)=33
              if ( kgds(1).eq.1.OR.kgds(1).eq.3 ) kgds(20)=43
              kgds(21)=igds(2)                   ! num of grid points
              do j=1,idefnum
                 kgds(21+j)=ideflist(j)
              enddo
           endif
        elseif (igds(5).eq.10) then       !  Mercator grid
           kgds(1)=1                 ! Grid Definition Template number
           kgds(2)=igdstmpl(8)            ! Ni
           kgds(3)=igdstmpl(9)            ! Nj
           kgds(4)=igdstmpl(10)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(11)/1000      ! Long of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(12),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(14)/1000      ! Lat of last grid point
           kgds(8)=igdstmpl(15)/1000      ! Long of last grid point
           kgds(9)=igdstmpl(13)/1000      ! Lat intersects earth
           kgds(10)=0
           kgds(11)=igdstmpl(16)          ! Scanning mode
           kgds(12)=igdstmpl(18)/1000     ! Di
           kgds(13)=igdstmpl(19)/1000     ! Dj
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
        elseif (igds(5).eq.30) then       ! Lambert Conformal Grid
           kgds(1)=3
           kgds(2)=igdstmpl(8)            ! Nx
           kgds(3)=igdstmpl(9)            ! Ny
           kgds(4)=igdstmpl(10)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(11)/1000      ! Long of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(12),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(14)/1000      ! Lon of orientation
           kgds(8)=igdstmpl(15)/1000      ! Dx
           kgds(9)=igdstmpl(16)/1000      ! Dy
           kgds(10)=igdstmpl(17)          ! Projection Center Flag
           kgds(11)=igdstmpl(18)          ! Scanning mode
           kgds(12)=igdstmpl(19)/1000     ! Lat in 1
           kgds(13)=igdstmpl(20)/1000     ! Lat in 2
           kgds(14)=igdstmpl(21)/1000     ! Lat of S. Pole of projection
           kgds(15)=igdstmpl(22)/1000     ! Lon of S. Pole of projection
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
        elseif (igds(5).eq.40) then       !  Gaussian Lat/Lon grid
           kgds(1)=4
           kgds(2)=igdstmpl(8)            ! Ni
           kgds(3)=igdstmpl(9)            ! Nj
           kgds(4)=igdstmpl(12)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(13)/1000      ! Long of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(14),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(15)/1000      ! Lat of last grid point
           kgds(8)=igdstmpl(16)/1000      ! Long of last grid point
           kgds(9)=igdstmpl(17)/1000      ! Di
           kgds(10)=igdstmpl(18)          ! N - Number of parallels
           kgds(11)=igdstmpl(19)          ! Scanning mode
           kgds(12)=0
           kgds(13)=0
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
        elseif (igds(5).eq.20) then       ! Polar Stereographic Grid
           kgds(1)=5
           kgds(2)=igdstmpl(8)            ! Nx
           kgds(3)=igdstmpl(9)            ! Ny
           kgds(4)=igdstmpl(10)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(11)/1000      ! Long of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(12),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(14)/1000      ! Lon of orientation
           kgds(8)=igdstmpl(15)/1000      ! Dx
           kgds(9)=igdstmpl(16)/1000      ! Dy
           kgds(10)=igdstmpl(17)          ! Projection Center Flag
           kgds(11)=igdstmpl(18)          ! Scanning mode
           kgds(12)=0
           kgds(13)=0
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
        elseif (igds(5).eq.204) then      ! Curvilinear Orthogonal
           kgds(1)=204
           kgds(2)=igdstmpl(8)            ! Ni
           kgds(3)=igdstmpl(9)            ! Nj
           kgds(4)=0
           kgds(5)=0
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(14),3) ) kgds(6)=kgds(6)+8
           kgds(7)=0
           kgds(8)=0
           kgds(9)=0
           kgds(10)=0
           kgds(11)=igdstmpl(19)          ! Scanning mode
           kgds(12)=0
           kgds(13)=0
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
           !
           !  Process irreg grid stuff, if necessary
           !
           if ( idefnum.ne.0 ) then
              if ( igdstmpl(8).eq.-1 ) then
                 kgds(2)=65535
                 kgds(9)=65535
              endif
              if ( igdstmpl(9).eq.-1 ) then
                 kgds(3)=65535
                 kgds(10)=65535
              endif
              kgds(19)=0
              kgds(20)=33
              if ( kgds(1).eq.1.OR.kgds(1).eq.3 ) kgds(20)=43
              kgds(21)=igds(2)                   ! num of grid points
              do j=1,idefnum
                 kgds(21+j)=ideflist(j)
              enddo
           endif
        elseif (igds(5).eq.32768) then    ! Rotate Lat/Lon grid
           kgds(1)=203                    ! Arakawa Staggerred E/B grid
           kgds(2)=igdstmpl(8)            ! Ni
           kgds(3)=igdstmpl(9)            ! Nj
           kgds(4)=igdstmpl(12)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(13)/1000      ! Lon of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(14),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(15)/1000      ! Lat of last grid point
           kgds(8)=igdstmpl(16)/1000      ! Lon of last grid point
           kgds(9)=igdstmpl(17)/1000      ! Di
           kgds(10)=igdstmpl(18)/1000     ! Dj
           kgds(11)=igdstmpl(19)          ! Scanning mode
           kgds(12)=0
           kgds(13)=0
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
           !
           !  Process irreg grid stuff, if necessary
           !
           if ( idefnum.ne.0 ) then
              if ( igdstmpl(8).eq.-1 ) then
                 kgds(2)=65535
                 kgds(9)=65535
              endif
              if ( igdstmpl(9).eq.-1 ) then
                 kgds(3)=65535
                 kgds(10)=65535
              endif
              kgds(19)=0
              kgds(20)=33
              if ( kgds(1).eq.1.OR.kgds(1).eq.3 ) kgds(20)=43
              kgds(21)=igds(2)                   ! num of grid points
              do j=1,idefnum
                 kgds(21+j)=ideflist(j)
              enddo
           endif
        elseif (igds(5).eq.32769) then    ! Rotate Lat/Lon grid
           kgds(1)=205                    ! Arakawa Staggerred for Non-E Stagger grid
           kgds(2)=igdstmpl(8)            ! Ni
           kgds(3)=igdstmpl(9)            ! Nj
           kgds(4)=igdstmpl(12)/1000      ! Lat of 1st grid point
           kgds(5)=igdstmpl(13)/1000      ! Lon of 1st grid point
           kgds(6)=0                      ! resolution and component flags
           if (igdstmpl(1)==2 ) kgds(6)=64
           if ( btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5) )
     &         kgds(6)=kgds(6)+128
           if ( btest(igdstmpl(14),3) ) kgds(6)=kgds(6)+8
           kgds(7)=igdstmpl(15)/1000      ! Lat of last grid point
           kgds(8)=igdstmpl(16)/1000      ! Lon of last grid point
           kgds(9)=igdstmpl(17)/1000      ! Di
           kgds(10)=igdstmpl(18)/1000     ! Dj
           kgds(11)=igdstmpl(19)          ! Scanning mode
           kgds(12)=igdstmpl(20)/1000
           kgds(13)=igdstmpl(21)/1000
           kgds(14)=0
           kgds(15)=0
           kgds(16)=0
           kgds(17)=0
           kgds(18)=0
           kgds(19)=0
           kgds(20)=255
           kgds(21)=0
           kgds(22)=0
        else
           Print *,'gdt2gds: Unrecognized GRIB2 GDT = 3.',igds(5)
           iret=1
           kgds(1:22)=0
           return
        endif
!
!   Can we determine NCEP grid number ?
!
        igrid=255
        do j=254,1,-1
        !do j=225,225
           kgds71=0
           kgds72=0
           call w3fi71(j,kgds71,ierr)
           if ( ierr.ne.0 ) cycle
           ! convert W to E for longitudes
           if ( kgds71(3).eq.0 ) then    ! lat/lon
              if ( kgds71(7).lt.0 ) kgds71(7)=360000+kgds71(7)
              if ( kgds71(10).lt.0 ) kgds71(10)=360000+kgds71(10)
           elseif ( kgds71(3).eq.1 ) then    ! mercator
              if ( kgds71(7).lt.0 ) kgds71(7)=360000+kgds71(7)
              if ( kgds71(10).lt.0 ) kgds71(10)=360000+kgds71(10)
           elseif ( kgds71(3).eq.3 ) then     ! lambert conformal
              if ( kgds71(7).lt.0 ) kgds71(7)=360000+kgds71(7)
              if ( kgds71(9).lt.0 ) kgds71(9)=360000+kgds71(9)
              if ( kgds71(18).lt.0 ) kgds71(18)=360000+kgds71(18)
           elseif ( kgds71(3).eq.4 ) then     ! Guassian lat/lon
              if ( kgds71(7).lt.0 ) kgds71(7)=360000+kgds71(7)
              if ( kgds71(10).lt.0 ) kgds71(10)=360000+kgds71(10)
           elseif ( kgds71(3).eq.5 ) then     ! polar stereographic
              if ( kgds71(7).lt.0 ) kgds71(7)=360000+kgds71(7)
              if ( kgds71(9).lt.0 ) kgds71(9)=360000+kgds71(9)
           endif
           call r63w72(idum,kgds,jdum,kgds72)
           if ( kgds72(3).eq.3 ) kgds72(14)=0    ! lambert conformal fix
           if ( kgds72(3).eq.1 ) kgds72(15:18)=0    ! mercator fix
           if ( kgds72(3).eq.5 ) kgds72(14:18)=0    ! polar str fix
c           print *,' kgds71(',j,')= ', kgds71(1:30)
c           print *,' kgds72       = ', kgds72(1:30)
           if ( all(kgds71.eq.kgds72) ) then
              igrid=j
              return
           endif
        enddo

        return
        end


!**********************************************************************************************************************************
! LICENSING
! Copyright (C) 2012-2016  National Renewable Energy Laboratory
!
!    This file is part of AeroDyn.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
!     http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!
!**********************************************************************************************************************************
!> Module for the old aerodynamic routines. This module is for loose coupling only, without linearization, because it does not
!! fully conform to the FAST framework. This module will eventually be replaced by AeroDyn (i.e., AeroDyn v15 [aerodyn.f90])
MODULE AeroDyn14

   USE AeroDyn14_Types
   USE AeroSubs
   USE NWTC_Library

   IMPLICIT NONE

   PRIVATE

   TYPE(ProgDesc), PARAMETER            :: AD14_Ver = ProgDesc( 'AeroDyn14', '', '' )

      ! ..... Public Subroutines ............

   PUBLIC :: AD14_Init                           ! Initialization routine
   PUBLIC :: AD14_End                            ! Ending routine (includes clean up)

   PUBLIC :: AD14_UpdateStates                   ! Loose coupling routine for solving for constraint states, integrating
                                                 !   continuous states, and updating discrete states
   PUBLIC :: AD14_CalcOutput                     ! Routine for computing outputs

CONTAINS
!----------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE AD14_Init( InitInp, u, p, x, xd, z, O, y, m, Interval, InitOut, ErrStat, ErrMess )
!..................................................................................................................................
   USE               AeroGenSubs,   ONLY: ElemOpen
   USE DWM
   IMPLICIT NONE

   TYPE(AD14_InitInputType),       INTENT(INOUT)  :: InitInp     ! Input data for initialization routine
   TYPE(AD14_InputType),           INTENT(  OUT)  :: u           ! An initial guess for the input; input mesh must be defined
   TYPE(AD14_ParameterType),       INTENT(  OUT)  :: p           ! Parameters
   TYPE(AD14_ContinuousStateType), INTENT(  OUT)  :: x           ! Initial continuous states
   TYPE(AD14_DiscreteStateType),   INTENT(  OUT)  :: xd          ! Initial discrete states
   TYPE(AD14_ConstraintStateType), INTENT(  OUT)  :: z           ! Initial guess of the constraint states
   TYPE(AD14_OtherStateType),      INTENT(  OUT)  :: O           ! Initial other states
   TYPE(AD14_OutputType),          INTENT(  OUT)  :: y           ! Initial system outputs (outputs are not calculated;
                                                                 !   only the output mesh is initialized)
   TYPE(AD14_MiscVarType),         INTENT(  OUT)  :: m           ! Misc/optimization variables
   REAL(DbKi),                     INTENT(INOUT)  :: Interval    ! Coupling interval in seconds: the rate that
                                                                 !   (1) AD14_UpdateStates() is called in loose coupling &
                                                                 !   (2) AD14_UpdateDiscState() is called in tight coupling.
                                                                 !   Input is the suggested time from the glue code;
                                                                 !   Output is the actual coupling interval that will be used
                                                                 !   by the glue code.
   TYPE(AD14_InitOutputType),      INTENT(  OUT)  :: InitOut     ! Output for initialization routine
   INTEGER(IntKi),                 INTENT(  OUT)  :: ErrStat     ! Error status of the operation
   CHARACTER(*),                   INTENT(  OUT)  :: ErrMess     ! Error message if ErrStat /= ErrID_None

      ! Internal variables
   REAL(ReKi)                       :: CosPrecone
   REAL(ReKi)                       :: DTip, ElemRad, Dhub, Rhub     ! variables for calculating hub- and tip-loss constants
   REAL(ReKi)                       :: HubRadius
!   REAL(ReKi)                       :: MeanWind
   REAL(ReKi)                       :: TipRadius
   REAL(ReKi)                       :: TmpVar
   REAL(ReKi)                       :: TmpPos(3)
   REAL(ReKi)                                :: TwrNodeHt                     ! The height of the current tower node.

   INTEGER                          :: IB, IE
   INTEGER                          :: IELM

!   CHARACTER(1024)                  :: Title

   INTEGER                                   :: Elem                          ! Index for mesh element.
   INTEGER                                   :: InterpIndx                 ! Index telling the interpolation routine where to start in the array.
   INTEGER                                   :: Node                          ! Index used to pull points out of the array of values at given node location.
   INTEGER                                   :: ErrStatLcL        ! Error status returned by called routines.

   CHARACTER(ErrMsgLen)                      :: ErrMessLcl          ! Error message returned by called routines.
   CHARACTER(*), PARAMETER                   :: RoutineName = 'AD14_Init'

         ! Initialize ErrStat

   ErrStat = ErrID_None
   ErrMess  = ""
   InterpIndx = 1

   CALL NWTC_Init( )

         ! Display the module information

   CALL DispNVD( AD14_Ver )

   InitOut%Ver = AD14_Ver
   m%FirstWarn = .TRUE.
   !-------------------------------------------------------------------------------------------------
   ! Set up AD variables
   !-------------------------------------------------------------------------------------------------

   p%LinearizeFlag     = .FALSE.             ! InitInp%LinearizeFlag
   p%Blade%BladeLength = InitInp%TurbineComponents%BladeLength
   p%DtAero            = Interval            ! set the default DT here; may be overwritten later, when we read the input file in AD14_GetInput()
   p%UseDWM            = InitInp%UseDWM

         ! Define parameters here:

   p%WrOptFile   = InitInp%WrSumFile

   p%NumBl   = SIZE( InitInp%TurbineComponents%Blade )
   IF ( p%NumBl < 1 ) THEN
      CALL SetErrStat( ErrID_Fatal,'AeroDyn cannot run without blades in the model.',ErrStat,ErrMess,RoutineName)
      RETURN
   END IF
!bjj: what's the difference between p%NumBl, p%Blade%NB, and InitInp%NumBl?
!MLB: Heck if I know!

         ! Define initial system states here:
   !-------------------------------------------------------------------------------------------------
   ! Read the AeroDyn14 input file and open the output file if requested
   ! bjj: these should perhaps be combined
   !-------------------------------------------------------------------------------------------------
   CALL AD14_GetInput(InitInp, P, x, xd, z, m, y, ErrStatLcl, ErrMessLcl )
      CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
      IF (ErrStat >= AbortErrLev ) RETURN

      ! allocate variables for aerodyn forces
   p%LinearizeFlag     = .FALSE.

   Interval = p%DtAero

   IF ( .NOT. ALLOCATED( m%StoredForces  )) THEN
      CALL AllocAry(m%StoredForces, 3,p%Element%NELM,p%NumBl,'m%StoredForces',ErrStatLcl,ErrMessLcl  )
         CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
   END IF
   IF ( .NOT. ALLOCATED( m%StoredMoments ))  THEN
      CALL AllocAry(m%StoredMoments, 3,p%Element%NELM,p%NumBl,'m%StoredForces',ErrStatLcl,ErrMessLcl  )
         CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
   END IF

   IF (.NOT. ALLOCATED(m%Element%W2) ) THEN
      CALL AllocAry(m%Element%W2, p%Element%NELM, p%NumBl,'m%Element%W2',ErrStatLcl,ErrMessLcl  )
         CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
   END IF

   IF (.NOT. ALLOCATED(m%Element%Alpha) ) THEN
      CALL AllocAry(m%Element%Alpha, p%Element%NELM, p%NumBl,'m%Element%Alpha',ErrStatLcl,ErrMessLcl  )
         CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
   END IF

   IF (.NOT. ALLOCATED(m%Element%PitNow) ) THEN
      CALL AllocAry(m%Element%PitNow, p%Element%NELM, p%NumBl,'m%Element%PitNow',ErrStatLcl,ErrMessLcl  )
         CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
   END IF
   IF (ErrStat >= AbortErrLev ) RETURN

   P%UnWndOut = -1
   P%UnElem = -1
   IF ( p%ElemPrn )  THEN
      CALL ElemOpen ( TRIM( InitInp%OutRootName )//'.AD.out', P, m, ErrStat, ErrMess, AD14_Ver )
         CALL SetErrStat( ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName)
         IF (ErrStat >= AbortErrLev ) RETURN
   END IF

   !-------------------------------------------------------------------------------------------------
   ! Calculate the rotor and hub radaii from the input values
   !-------------------------------------------------------------------------------------------------
   HubRadius = DOT_PRODUCT( InitInp%TurbineComponents%Blade(1)%Position(:)        &
                          - InitInp%TurbineComponents%Hub%Position(:),            &
                            InitInp%TurbineComponents%Blade(1)%Orientation(3,:) )

   DO IB = 2,p%NumBl
      TmpVar    = DOT_PRODUCT( InitInp%TurbineComponents%Blade(IB)%Position(:)    &
                             - InitInp%TurbineComponents%Hub%Position(:),         &
                               InitInp%TurbineComponents%Blade(IB)%Orientation(3,:) )
      IF ( ABS( TmpVar - HubRadius ) > 0.001 ) THEN ! within 1 mm
         CALL ProgWarn( ' AeroDyn\AD14_Init() calculated HubRadius is not the same for all '// &
                           'blades. Using value from blade 1.' )
         EXIT
      END IF
   END DO !IB

   TipRadius = InitInp%TurbineComponents%BladeLength + HubRadius

   CosPrecone = ASIN( DOT_PRODUCT( InitInp%TurbineComponents%Blade(1)%Orientation(3,:), &
                                   InitInp%TurbineComponents%Hub%Orientation(1,:) ) )  ! precone angle -- do COS later

   DO IB = 2,p%NumBl
      TmpVar  = ASIN( DOT_PRODUCT( InitInp%TurbineComponents%Blade(IB)%Orientation(3,:), &
                                   InitInp%TurbineComponents%Hub%Orientation(1,:) ) )
      IF ( ABS( TmpVar - CosPrecone ) > 0.009 ) THEN     ! within ~ 1/2 degree
         CALL ProgWarn( ' AeroDyn\AD14_Init() calculated precone angle is not the same for all'// &
                           ' blades. Using value from blade 1.' )
         EXIT
      END IF
   END DO !IBld

   CosPrecone = COS( CosPrecone )

   p%Blade%R = TipRadius * CosPrecone
   RHub = HubRadius * CosPrecone
   p%HubRad = RHub

      ! Check that the AeroDyn input DR and RElm match (use the HubRadius and TipRadius to verify)
      ! before using them to calculate the tip- and hub-loss constants
   CALL CheckRComp( P, x, xd, z, m, y, ErrStat, ErrMess, &
                    InitInp%ADFileName, HubRadius, TipRadius )

   IF ( ErrStat /= ErrID_None ) RETURN

   !-------------------------------------------------------------------------------------------------
   ! Calculate tip-loss constants
   !-------------------------------------------------------------------------------------------------
   DO IElm = 1,p%Element%NElm  ! Loop through all blade elements

      ElemRad = p%Element%RELM(IElm)*CosPrecone

      IF( ElemRad == 0.0 )  THEN  !BJJ: should this be 0.001 (or another small number) instead of exactly 0.0?
         CALL SetErrStat( ErrID_Fatal,'Error calculating tip loss constant for element '//TRIM(Int2LStr(IElm))//&
                          '. Division by zero.',ErrStat,ErrMess,RoutineName)

         RETURN
      ELSE
         DTip         = p%Blade%R - ElemRad
         p%Element%TLCNST(IElm) = 0.5 * p%NumBl * DTip / ElemRad
      ENDIF

   ENDDO             ! IElm - all blade elements

   !-------------------------------------------------------------------------------------------------
   ! Calculate hub-loss constants
   !-------------------------------------------------------------------------------------------------
   IF ( RHub > 0.001 )  THEN

      DO Ielm = 1,p%Element%NELM  ! Loop through all blade elements

         ElemRad = p%Element%RELM(Ielm)*CosPrecone  ! Use only the precone angle of blade 1 (assumed very similar to other blades)

         DHub         = ElemRad - RHub
         p%Element%HLCNST(Ielm) = 0.5 * p%NumBl * DHub / RHub

      ENDDO             ! IELM - all blade elements

   ELSE

      p%Element%HLCNST(:) = 0.0

   ENDIF

      !-------------------------------------------------------------------------------------------------
      ! Interpolate the tower diameter at ElastoDyn's tower nodes if we will be computing tower aerodynamics.
      !-------------------------------------------------------------------------------------------------

   IF ( p%TwrProps%CalcTwrAero )  THEN

         !-------------------------------------------------------------------------------------------------
         ! IMPORTANT NOTES:
         !     o  Supposedly, the glue code will not try to do anything with the tower-aero mesh if is is
         !        not created, so the creation is inside the test for CalcTwrAero.
         !     o  The tower properties from AeroDyn's tower file are for heights from the origin (ground or
         !        MSL) to the hub height--not the top of the tower.
         !     o  For now, we are allowing only one set of Cd for the entire tower.
         !     o  InterpIndx is initialize to 1 at compile time.
         !-------------------------------------------------------------------------------------------------

         ! Create the mesh for the tower aerodynamics.

      CALL MeshCreate ( BlankMesh       = u%Twr_InputMarkers      &
                      , IOS             = COMPONENT_INPUT         &
                      , NNodes          = InitInp%NumTwrNodes     &
                      , Orientation     = .TRUE.                  &
                      , TranslationDisp = .TRUE.                  &
                      , TranslationVel  = .TRUE.                  &
                      , ErrStat         = ErrStatLcl              &
                      , ErrMess         = ErrMessLcl              )

      CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
      IF ( ErrStat >= AbortErrLev )  RETURN

         ! Set the positions of the nodes.  MeshCreate() allocated the Position array.

      DO Node = 1,u%Twr_InputMarkers%Nnodes
         CALL MeshPositionNode ( Mesh  = u%Twr_InputMarkers          &
                                ,INode = Node                        &
                                ,Pos   = InitInp%TwrNodeLocs(:,Node) &
                                ,ErrStat   = ErrStatLcl              &
                                ,ErrMess   = ErrMessLcl              )
         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN

      END DO

         ! Construct the tower with Line-2 elements.

      DO Elem=1,u%Twr_InputMarkers%Nnodes-1

         CALL MeshConstructElement ( Mesh     = u%Twr_InputMarkers &
                                   , Xelement = ELEMENT_LINE2      &
                                   , P1       = Elem               &
                                   , P2       = Elem+1             &
                                   , ErrStat  = ErrStatLcl         &
                                   , ErrMess  = ErrMessLcl         )

         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN

      ENDDO

         ! Commit the mesh to the funny farm.

      CALL MeshCommit ( u%Twr_InputMarkers, ErrStatLcl, ErrMessLcl )
         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN

         ! Copy the input mesh to create the output mesh.  Does

      CALL MeshCopy ( SrcMesh  = u%Twr_InputMarkers &
                    , DestMesh = y%Twr_OutputLoads  &
                    , CtrlCode = MESH_SIBLING       &
                    , Force    = .TRUE.             &
                    , ErrStat  = ErrStatLcl         &
                    , ErrMess  = ErrMessLcl         )

         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN

         ! Check to ensure that the user did not specify more than one set of Cd(Re) tables.  Temporary restriction.

      IF ( p%TwrProps%NTwrCD /= 1 )  THEN
         CALL SetErrStat(ErrID_Fatal,'You must have one and only one set of drag coefficients for the AeroDyn tower file.',ErrStat,ErrMess,RoutineName )
         RETURN
      END IF

         ! Build the TwrNodeWidth array.

      p%TwrProps%NumTwrNodes = InitInp%NumTwrNodes

      IF (.NOT. ALLOCATED( p%TwrProps%TwrNodeWidth ) ) THEN
         CALL AllocAry( p%TwrProps%TwrNodeWidth, p%TwrProps%NumTwrNodes, "array for tower widths at ED node locations", ErrStatLcl, ErrMessLcl )
         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN
      END IF

      DO Node=1,p%TwrProps%NumTwrNodes

         TwrNodeHt = InitInp%TwrNodeLocs(3,Node)/p%Rotor%HH

         p%TwrProps%TwrNodeWidth(Node) = InterpStp( TwrNodeHt, p%TwrProps%TwrHtFr, p%TwrProps%TwrWid, InterpIndx, p%TwrProps%NTwrHT )

      END DO ! Node

   ELSE
      u%Twr_InputMarkers%Nnodes = 0
      y%Twr_OutputLoads%Nnodes  = 0
   END IF ! ( p%TwrProps%CalcTwrAero )

   !-------------------------------------------------------------------------------------------------
   ! Write the summary (opt) file, then close it
   !-------------------------------------------------------------------------------------------------

   IF (p%WrOptFile) THEN

      CALL ADOut(InitInp, P, m, AD14_Ver, TRIM(InitInp%OutRootName)//'.AD.sum', ErrStatLcl, ErrMessLcl )
         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN

   ENDIF

   !-------------------------------------------------------------------------------------------------
   ! Initialize the inputs from the wind inflow module
   !-------------------------------------------------------------------------------------------------
   CALL AllocAry( u%InflowVelocity, 3, p%Element%NElm*p%NumBl + u%Twr_InputMarkers%Nnodes, 'u%InflowVelocity', ErrStatLcl, ErrMessLcl )
         CALL SetErrStat(ErrStatLcl,ErrMessLcl,ErrStat,ErrMess,RoutineName )
         IF ( ErrStat >= AbortErrLev )  RETURN
   u%InflowVelocity = 0.0_ReKi

   !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   ! Calling the DWM
   !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   IF ( p%UseDWM ) THEN
      ! InitInp%DWM%IfW%InputFileName is already set in FAST

         ! bjj: all this stuff should be put in DWM_Init.....>
      p%DWM%RR              = p%Blade%R
      p%DWM%BNum            = p%NumBl
      !p%DWM%ElementNum      = m%ElOut%NumElOut  !bjj: NumElOut is the number of elements to be printed in an output file. I really think you want the number of blade elements. I guess we should check that NumElOut is the same as p%Element%NElm
      p%DWM%ElementNum      = p%Element%NElm      ! yj: 1/18/2016
      p%DWM%air_density     = p%Wind%Rho

      IF (.NOT. ALLOCATED(m%DWM%Nforce    )) ALLOCATE ( m%DWM%Nforce(    p%Element%NElm,p%NumBl),STAT=ErrStatLcl);CALL SetErrStat(ErrStatLcl, 'Error allocating DWM Nforce array', ErrStat,ErrMess,RoutineName )
      IF (.NOT. ALLOCATED(m%DWM%blade_dr  )) ALLOCATE ( m%DWM%blade_dr(  p%Element%NElm),        STAT=ErrStatLcl);CALL SetErrStat(ErrStatLcl, 'Error allocating DWM blade_dr array', ErrStat,ErrMess,RoutineName )
      IF (.NOT. ALLOCATED(p%DWM%ElementRad)) ALLOCATE ( p%DWM%ElementRad(p%Element%NElm),        STAT=ErrStatLcl);CALL SetErrStat(ErrStatLcl, 'Error allocating DWM ElementRad array', ErrStat,ErrMess,RoutineName )
      if (errStat >= AbortErrLev) return

      m%DWM%blade_dr = p%Blade%DR(:)
      p%DWM%ElementRad = p%Element%RELM(:)

      CALL DWM_Init( InitInp%DWM, m%DWM_Inputs, p%DWM, x%DWM, xd%DWM, z%DWM, O%DWM, m%DWM_Outputs, m%DWM, Interval, InitOut%DWM, ErrStatLcl, ErrMessLcl)

      CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
      IF (ErrStat >= AbortErrLev) RETURN

   END IF !UseDWM

   !-------------------------------------------------------------------------------------------------
   ! Turn off dynamic inflow for wind less than 8 m/s (per DJL: 8 m/s is really just an empirical guess)
   ! DJL: Comment out this code when using new proposed GDW check in ELEMFRC
   ! BJJ: FIX THIS!!!!
   !-------------------------------------------------------------------------------------------------

   ! BJJ: can't put this here b/c we need InitInp%MWS from InflowWind
   !IF (p%DynInfl) THEN
   !
   !   IF ( InitInp%MWS  < 8.0 ) THEN
   !      p%DynInfl = .FALSE.
   !      CALL SetErrStat(ErrID_Info,'Estimated average inflow wind speed is less than 8 m/s. Dynamic Inflow will be turned off.',ErrStat,ErrMess,RoutineName )
   !      IF ( ErrStat >= AbortErrLev )  RETURN
   !   END IF
   !
   !ENDIF

   !-------------------------------------------------------------------------------------------------
   ! Set initial guesses for inputs:
   !-------------------------------------------------------------------------------------------------

   !..........
   ! u%TurbineComponents
   !..........

   CALL AD14_CopyAeroConfig( InitInp%TurbineComponents, u%TurbineComponents, MESH_NEWCOPY, ErrStatLcl, ErrMessLcl )
      CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
      IF (ErrStat >= AbortErrLev) RETURN

   !..........
   ! u%InputMarkers (blade meshes):
   !..........

   ALLOCATE( u%InputMarkers(p%NumBl), STAT=ErrStatLcl )
   IF (ErrStatLcl /= 0 ) THEN
      CALL SetErrStat ( ErrID_Fatal, 'Could not allocate u%InputMarkers (meshes)', ErrStat,ErrMess,RoutineName )
      RETURN
   END IF

   DO IB = 1, p%NumBl
      CALL MeshCreate( BlankMesh      = u%InputMarkers(IB)    &
                     ,IOS            = COMPONENT_INPUT        &
                     ,NNodes         = p%Element%NELM         &
                     ,Orientation    = .TRUE.                 &
                     ,TranslationVel = .TRUE.                 &
                     ,TranslationAcc = .TRUE.                 &  !bjj: added for MHK turbines
                     ,RotationVel    = .TRUE.                 &
                     ,nScalars       = 2                      &  ! scalar 1 is W, scalar 2 is Alpha
                     ,ErrStat        = ErrStatLcl             &
                     ,ErrMess        = ErrMessLcl             )

      CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
      IF (ErrStat >= AbortErrLev) RETURN

      ! create the elements
      DO IE = 1, p%Element%NELM-1 ! construct the blades into Line2 elements
         CALL MeshConstructElement ( Mesh = u%InputMarkers(IB)    &
                                  ,Xelement = ELEMENT_LINE2       &
                                  ,P1       = IE                  &
                                  ,P2       = IE+1                &
                                  ,ErrStat  = ErrStatLcl          &
                                  ,ErrMess  = ErrMessLcl          )
         CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
         IF (ErrStat >= AbortErrLev) RETURN

      ENDDO

      ! position/orient the nodes
      DO IE = 1, p%Element%NELM
         TmpPos(1) = 0.
         TmpPos(2) = 0.
         TmpPos(3) = p%Element%Relm(IE) - HubRadius
         CALL MeshPositionNode ( Mesh = u%InputMarkers(IB)              &
                                 ,INode = IE                            &
                                 ,Pos= TmpPos                           &  ! this info comes from FAST (not yet)
                                 ,ErrStat   = ErrStatLcl                &
                                 ,ErrMess   = ErrMessLcl                )
         CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
         IF (ErrStat >= AbortErrLev) RETURN

         ! RELATIVE ORIENTATION OF BLADE ELEMENTS
         u%InputMarkers(IB)%Orientation(1,1,IE) = COS( P%Element%TWIST(IE) )
         u%InputMarkers(IB)%Orientation(2,1,IE) = SIN( P%Element%TWIST(IE) )
         u%InputMarkers(IB)%Orientation(3,1,IE) = SIN( P%Element%TWIST(IE) )
         u%InputMarkers(IB)%Orientation(1,2,IE) = -1. * u%InputMarkers(IB)%Orientation(2,1,IE)
         u%InputMarkers(IB)%Orientation(2,2,IE) =       u%InputMarkers(IB)%Orientation(1,1,IE)
         u%InputMarkers(IB)%Orientation(3,2,IE) = 0.0
         u%InputMarkers(IB)%Orientation(1,3,IE) = 0.0
         u%InputMarkers(IB)%Orientation(2,3,IE) = 0.0
         u%InputMarkers(IB)%Orientation(3,3,IE) = 1.0
      ENDDO

       CALL MeshCommit ( Mesh = u%InputMarkers(IB)    &
                        ,ErrStat  = ErrStatLcl        &
                        ,ErrMess  = ErrMessLcl        )
         CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
         IF (ErrStat >= AbortErrLev) RETURN

   ENDDO

   !..........
   ! u%Twr_InputMarkers (tower meshes):
   !..........

   !bjj: done above in section for IF Tower Loads is on

   !..........
   ! u%MulTabLoc:
   !..........

   IF (.NOT. ALLOCATED(u%MulTabLoc)) THEN
      ALLOCATE( u%MulTabLoc(p%Element%NELM, p%NumBl), STAT = ErrStatLcl )
      IF (ErrStatLcl /= 0) THEN
         CALL SetErrStat ( ErrID_Fatal, 'Could not allocate u%MulTabLoc', ErrStat,ErrMess,RoutineName )
         RETURN
      END IF
   END IF

   u%MulTabLoc(:,:) = 0.0

   !-------------------------------------------------------------------------------------------------
   ! Allocate space for outputs and set up output meshes:
   !-------------------------------------------------------------------------------------------------

   !..........
   ! y%OutputLoads (blade meshes):
   !..........

   ALLOCATE( y%OutputLoads(p%NumBl), STAT = ErrStatLcl )
      IF (ErrStatLcl /= 0) THEN
         CALL SetErrStat ( ErrID_Fatal, 'Could not allocate y%OutputLoads (meshes)', ErrStat,ErrMess,RoutineName )
         RETURN
      END IF

   DO IB = 1, p%NumBl

       CALL MeshCopy ( SrcMesh  = u%InputMarkers(IB)  &
                      ,DestMesh = y%OutputLoads(IB)   &
                      ,CtrlCode = MESH_SIBLING        &
                      ,Force    = .TRUE.              &
                      ,Moment   = .TRUE.              &
                      ,ErrStat  = ErrStatLcl          &
                      ,ErrMess  = ErrMessLcl          )
         CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,RoutineName )
         IF (ErrStat >= AbortErrLev) RETURN
   ENDDO

   !..........
   ! y%Twr_OutputLoads (tower meshes):
   !..........

   !bjj: done above in section for IF Tower Loads is on

   !-------------------------------------------------------------------------------------------------
   ! Initialize AeroDyn variables not initialized elsewhere (except in module initialization)
   ! and return
   !-------------------------------------------------------------------------------------------------
   m%InducedVel%SumInfl  = 0.0_ReKi
   m%Rotor%AvgInfl       = 0.0_ReKi
   m%OldTime             = 0.0_DbKi
   m%SuperSonic          = .FALSE.
   m%NoLoadsCalculated   = .TRUE.

   p%TwoPiNB     = TwoPi / REAL( p%NumBl, ReKi )

   DO ie = 1, maxInfl
      p%DynInflow%xMinv(ie) = PIBY2 / hfunc(MRvector(ie), NJvector(ie))   !bjj: this is really just a Fortran parameter, too.
   END DO !ie

   InitOut%AirDens = p%Wind%Rho

   RETURN

END SUBROUTINE AD14_Init
!----------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE AD14_End( u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMess )
! This routine is called at the end of the simulation.
!..................................................................................................................................
      USE DWM_Types
      USE DWM

      TYPE(AD14_InputType),           INTENT(INOUT)  :: u           ! System inputs
      TYPE(AD14_ParameterType),       INTENT(INOUT)  :: p           ! Parameters
      TYPE(AD14_ContinuousStateType), INTENT(INOUT)  :: x           ! Continuous states
      TYPE(AD14_DiscreteStateType),   INTENT(INOUT)  :: xd          ! Discrete states
      TYPE(AD14_ConstraintStateType), INTENT(INOUT)  :: z           ! Constraint states
      TYPE(AD14_OtherStateType),      INTENT(INOUT)  :: OtherState  ! Other states
      TYPE(AD14_OutputType),          INTENT(INOUT)  :: y           ! System outputs
      TYPE(AD14_MiscVarType),         INTENT(INOUT)  :: m           ! Misc/optimization variables
      INTEGER(IntKi),                 INTENT(  OUT)  :: ErrStat     ! Error status of the operation
      CHARACTER(*),                   INTENT(  OUT)  :: ErrMess     ! Error message if ErrStat /= ErrID_None

         ! Initialize ErrStat

      ErrStat = ErrID_None
      ErrMess  = ""

         ! Place any last minute operations or calculations here:

      IF (p%UseDWM ) THEN
         !----- Call the DWM -------

         CALL DWM_End( m%DWM_Inputs, p%DWM, x%DWM, xd%DWM, z%DWM, OtherState%DWM, m%DWM_Outputs, m%DWM, ErrStat, ErrMess )
      END IF ! UseDWM

      !--------------------------

         ! Close files here:

      ! AD14_IOParams
   IF (P%UnEc > 0)    CLOSE(P%UnEc) ! not currently used

   IF (P%UnWndOut > 0) CLOSE(P%UnWndOut)
   IF (P%UnElem   > 0) CLOSE(P%UnElem)

         ! Destroy the input data:

      CALL AD14_DestroyInput( u, ErrStat, ErrMess )

         ! Destroy the parameter data:

      CALL AD14_DestroyParam( p, ErrStat, ErrMess )

         ! Destroy the state data:

      CALL AD14_DestroyContState(   x,           ErrStat, ErrMess )
      CALL AD14_DestroyDiscState(   xd,          ErrStat, ErrMess )
      CALL AD14_DestroyConstrState( z,           ErrStat, ErrMess )
      CALL AD14_DestroyOtherState(  OtherState,  ErrStat, ErrMess )

      CALL AD14_DestroyMisc( m, ErrStat, ErrMess )

         ! Destroy the output data:

      CALL AD14_DestroyOutput( y, ErrStat, ErrMess )

END SUBROUTINE AD14_End
!----------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE AD14_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, ErrStat, ErrMess )
! Loose coupling routine for solving for constraint states, integrating continuous states, and updating discrete states
! Constraint states are solved for input Time; Continuous and discrete states are updated for Time + Interval
!..................................................................................................................................

      REAL(DbKi),                           INTENT(IN   ) :: t           ! Current simulation time in seconds
      INTEGER(IntKi),                       INTENT(IN   ) :: n           ! Current simulation time step n = 0,1,...
      TYPE(AD14_InputType),                 INTENT(INOUT) :: u(:)        ! Inputs at utimes (out only for mesh record-keeping in ExtrapInterp routine)
      REAL(DbKi),                           INTENT(IN   ) :: utimes(:)   ! Times associated with u(:), in seconds
      TYPE(AD14_ParameterType),             INTENT(IN   ) :: p           ! Parameters
      TYPE(AD14_ContinuousStateType),       INTENT(INOUT) :: x           ! Input: Continuous states at t;
                                                                         !   Output: Continuous states at t + Interval
      TYPE(AD14_DiscreteStateType),         INTENT(INOUT) :: xd          ! Input: Discrete states at t;
                                                                         !   Output: Discrete states at t  + Interval
      TYPE(AD14_ConstraintStateType),       INTENT(INOUT) :: z           ! Input: Constraint states at t;
                                                                         !   Output: Constraint states at t + Interval
      TYPE(AD14_OtherStateType),            INTENT(INOUT) :: OtherState  ! Input: Other states at t;
                                                                         !   Output: Other states at t + Interval
      TYPE(AD14_MiscVarType),               INTENT(INOUT) :: m           ! Misc/optimization variables
      INTEGER(IntKi),                       INTENT(  OUT) :: ErrStat     ! Error status of the operation
      CHARACTER(*),                         INTENT(  OUT) :: ErrMess     ! Error message if ErrStat /= ErrID_None

         ! Local variables

      TYPE(AD14_ContinuousStateType)                 :: dxdt        ! Continuous state derivatives at Time
      TYPE(AD14_ConstraintStateType)                 :: z_Residual  ! Residual of the constraint state equations (Z)

!      INTEGER(IntKi)                                    :: ErrStat2    ! Error status of the operation (occurs after initial error)
!      CHARACTER(ErrMsgLen)                              :: ErrMess2     ! Error message if ErrStat2 /= ErrID_None

         ! Initialize ErrStat

      ErrStat = ErrID_None
      ErrMess  = ""

   ! AeroDyn v14 DOES actually have states, but they are updated in CalcOutput because no one ever took the time to
   ! identify which variables are states.

END SUBROUTINE AD14_UpdateStates

!----------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE AD14_CalcOutput( Time, u, p, x, xd, z, O, y, m, ErrStat, ErrMess )
! Routine for computing outputs, used in both loose and tight coupling.
!..................................................................................................................................

      USE               AeroGenSubs,   ONLY: ElemOut
      USE               DWM_Types
      USE               DWM

      REAL(DbKi),                     INTENT(IN   )  :: Time        ! Current simulation time in seconds
      TYPE(AD14_InputType),           INTENT(INOUT)  :: u           ! Inputs at Time
      TYPE(AD14_ParameterType),       INTENT(IN   )  :: p           ! Parameters
      TYPE(AD14_ContinuousStateType), INTENT(IN   )  :: x           ! Continuous states at Time
      TYPE(AD14_DiscreteStateType),   INTENT(IN   )  :: xd          ! Discrete states at Time
      TYPE(AD14_ConstraintStateType), INTENT(INOUT)  :: z           ! Constraint states at Time
      TYPE(AD14_OtherStateType),      INTENT(IN   )  :: O           ! Other states at Time
      TYPE(AD14_OutputType),          INTENT(INOUT)  :: y           ! Outputs computed at Time (Input only so that mesh con-
                                                                       !   nectivity information does not have to be recalculated)
      TYPE(AD14_MiscVarType),         INTENT(INOUT)  :: m           ! Misc/optimization variables
      INTEGER(IntKi),                 INTENT(  OUT)  :: ErrStat     ! Error status of the operation
      CHARACTER(*),                   INTENT(  OUT)  :: ErrMess     ! Error message if ErrStat /= ErrID_None

      ! Local variables
   REAL(DbKi), PARAMETER      :: OnePlusEpsilon = 1 + EPSILON(Time)

   REAL(ReKi)                 :: VelNormalToRotor2
   REAL(ReKi)                 :: VTWind
   REAL(ReKi)                 :: VNWind
   REAL(ReKi)                 :: VNElement
   REAL(ReKi)                 :: VTElement
   REAL(ReKi)                 :: VN_ind
   REAL(ReKi)                 :: VT_ind
   REAL(ReKi)                 :: VN
   REAL(ReKi)                 :: VT
   REAL(ReKi)                 :: VTTotal
   REAL(ReKi)                 :: DFN
   REAL(ReKi)                 :: DFT
   REAL(ReKi)                 :: PMA
   REAL(ReKi)                 :: SPitch                     ! sine of PitNow
   REAL(ReKi)                 :: CPitch                     ! cosine of PitNow
   REAL(ReKi)                 :: Phi                        ! Local value of Phi

   REAL(ReKi)                 :: AvgVelNacelleRotorFurlYaw
   REAL(ReKi)                 :: AvgVelTowerBaseNacelleYaw
   REAL(ReKi)                 :: AvgVelTowerBaseYaw
   REAL(ReKi)                 :: AzimuthAngle
   REAL(ReKi)                 :: rNacelleHub   (2)
   REAL(ReKi)                 :: rLocal
   REAL(ReKi)                 :: rRotorFurlHub (2)
   REAL(ReKi)                 :: rTowerBaseHub (2)

   REAL(ReKi)                 :: tmpVector     (3)
   REAL(ReKi)                 :: norm_Vector   (3) ! Unit vector normal to chord
   REAL(ReKi)                 :: tang_Vector   (3) ! Unit vector tangent to chord
   REAL(ReKi)                 :: VelocityVec   (3)

   INTEGER                    :: ErrStatLcL        ! Error status returned by called routines.
   INTEGER                    :: IBlade
   INTEGER                    :: IElement
   INTEGER                    :: Node              ! Node index.

   INTEGER                    :: I
   CHARACTER(ErrMsgLen)       :: ErrMessLcl          ! Error message returned by called routines.

   CHARACTER(*), PARAMETER                   :: RoutineName = 'AD14_AeroSubs' !KS Not sure why I added this

   ! Initialize ErrStat
      ErrStat = ErrID_None
      ErrMess  = ""

   !-------------------------------------------------------------------------------------------------
   ! Determine if loads should be recalculated or just returned
   !-------------------------------------------------------------------------------------------------
      ! NOTE: Time is scaled by OnePlusEps to ensure that loads are calculated at every
   !       time step when DTAero = DT, even in the presence of numerical precision errors.

   IF ( m%NoLoadsCalculated .OR. ( Time*OnePlusEpsilon - m%OldTime ) >= p%DTAERO )  THEN
         ! It's time to update the aero forces

         ! First we reset the DTAERO parameters for next time
      m%DT      = Time - m%OldTime     !bjj: DT = 0 on first step,
                                       !but the subroutines that use DT check for NoLoadsCalculated (or time > 0)
      m%OldTime = Time

   ELSE IF ( .NOT. p%LinearizeFlag ) THEN

         ! Return the previously-calculated loads

!      CurrentOutputs = ADCurrentLoads

      DO IBlade=1,p%NumBl
       DO IElement=1,p%Element%Nelm
         y%OutputLoads(IBlade)%Force(:,IElement)  = m%StoredForces(:,IElement,IBlade)
         y%OutputLoads(IBlade)%Moment(:,IElement) = m%StoredMoments(:,IElement,IBlade)
       ENDDO
      ENDDO

      IF ( m%FirstWarn ) THEN
         CALL SetErrStat ( ErrID_Warn, 'AeroDyn was designed for an explicit-loose coupling scheme. '//&
            'Using last calculated values from AeroDyn on all subsequent calls until time is advanced. '//&
            'Warning will not be displayed again.', ErrStat,ErrMess,'AD14_CalcOutput' )
         m%FirstWarn = .FALSE.
         IF (ErrStat >= AbortErrLev) THEN
            CALL CleanUp()
            RETURN
         END IF
      END IF

      RETURN

   ENDIF

   !-------------------------------------------------------------------------------------------------
   ! Calculate the forces and moments for the blade: SUBROUTINE AeroFrcIntrface( FirstLoop, JElemt, DFN, DFT, PMA )
   !-------------------------------------------------------------------------------------------------

      ! calculate rotor speed
      ! note: Subtracting the RotorFurl rotational velocity for REVS is needed to get the
      ! same answers as before v13.00.00. RotorFurl shouldn't be needed.

   m%Rotor%REVS = ABS( DOT_PRODUCT( u%TurbineComponents%Hub%RotationVel(:) - u%TurbineComponents%RotorFurl%RotationVel(:), &
                                    u%TurbineComponents%Hub%Orientation(1,:) ) )

      ! calculate yaw angle
      ! note: YawAng should use the Hub instead of the RotorFurl, but it is calculated this way to
      ! get the same answers as previous version.
   m%Rotor%YawAng = ATAN2( -1.*u%TurbineComponents%RotorFurl%Orientation(1,2), u%TurbineComponents%RotorFurl%Orientation(1,1) )
   m%Rotor%SYaw   = SIN( m%Rotor%YawAng )
   m%Rotor%CYaw   = COS( m%Rotor%YawAng )

      ! tilt angle
      ! note: tilt angle should use the Hub instead of RotorFurl, but it needs hub to get the same
      ! answers as the version before v13.00.00

   m%Rotor%Tilt = ATAN2( u%TurbineComponents%RotorFurl%Orientation(1,3), &
                         SQRT( u%TurbineComponents%RotorFurl%Orientation(1,1)**2 + &
                         u%TurbineComponents%RotorFurl%Orientation(1,2)**2 ) )

   m%Rotor%CTilt     = COS( m%Rotor%Tilt )
   m%Rotor%STilt     = SIN( m%Rotor%Tilt )

      ! HubVDue2Yaw - yaw velocity due solely to yaw

  AvgVelNacelleRotorFurlYaw = u%TurbineComponents%RotorFurl%RotationVel(3) - u%TurbineComponents%Nacelle%RotationVel(3)
  AvgVelTowerBaseNacelleYaw = u%TurbineComponents%Nacelle%RotationVel(3)   - u%TurbineComponents%Tower%RotationVel(3)
  AvgVelTowerBaseYaw        = u%TurbineComponents%Tower%RotationVel(3)

  rRotorFurlHub(1:2)        = u%TurbineComponents%Hub%Position(1:2) - u%TurbineComponents%RotorFurl%Position(1:2)
  rNacelleHub(1:2)          = u%TurbineComponents%Hub%Position(1:2) - u%TurbineComponents%Nacelle%Position(1:2)
  rTowerBaseHub(1:2)        = u%TurbineComponents%Hub%Position(1:2) - u%TurbineComponents%Tower%Position(1:2)

  m%Rotor%YawVel =   ( AvgVelNacelleRotorFurlYaw * rRotorFurlHub(2) + AvgVelTowerBaseNacelleYaw * rNacelleHub(2) &
                         + AvgVelTowerBaseYaw * rTowerBaseHub(2) ) * m%Rotor%SYaw &
                  - ( AvgVelNacelleRotorFurlYaw * rRotorFurlHub(1) + AvgVelTowerBaseNacelleYaw * rNacelleHub(1) &
                         + AvgVelTowerBaseYaw * rTowerBaseHub(1) ) * m%Rotor%CYaw

   !.................................................................................................
   ! start of NewTime routine
   !.................................................................................................

   m%Rotor%AvgInfl = m%InducedVel%SumInfl * 2.0 / (p%Blade%R*p%Blade%R*p%NumBl)  ! Average inflow from the previous time step
   m%InducedVel%SumInfl = 0.0   ! reset to sum for the current time step

   CALL DiskVel(Time, P, m, u%AvgInfVel, ErrStatLcl, ErrMessLcl)  ! Get a sort of "Average velocity" - sets a bunch of stored variables...
      CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput/DiskVel' )
      IF (ErrStat >= AbortErrLev) THEN
         CALL CleanUp()
         RETURN
      END IF

   IF ( P%DStall ) CALL BedUpdate( m )

   ! Enter the dynamic inflow routines here

   IF ( p%Wake )  THEN
      CALL Inflow(Time, P, m, ErrStatLcl, ErrMessLcl)
         CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput/Inflow' )
         IF (ErrStat >= AbortErrLev) THEN
            CALL CleanUp()
            RETURN
         END IF
   END IF

       !bjj: perhaps we should send NoLoadsCalculated to initialize dynamic inflow [subroutine Infinit()]
       !bjj: instead of the check that time > 0...?

   !.................................................................................................
   ! end of NewTime routine
   !.................................................................................................

      ! Set blade element pitches
   DO IBlade = 1,p%NumBl
      DO IElement = 1,p%Element%NElm
            ! calculate element pitch
         m%Element%PitNow(IElement,IBlade)   = -1.*ATAN2( -1.*DOT_PRODUCT( u%TurbineComponents%Blade(IBlade)%Orientation(1,:),    &
                                                           u%InputMarkers(IBlade)%Orientation(2,:,IElement) ) , &
                                              DOT_PRODUCT( u%TurbineComponents%Blade(IBlade)%Orientation(1,:),    &
                                                           u%InputMarkers(IBlade)%Orientation(1,:,IElement) )   )
      ENDDO
   ENDDO

   Node = 0
   ! --- Loop on blades
   DO IBlade = 1,p%NumBl

         ! calculate the azimuth angle ( we add pi because AeroDyn defines 0 as pointing downward)
         ! note: the equation below should use TurbineComponents%Blade markers, but this is used to get the
         ! same answers as the previous version (before v13.00.00)

      AzimuthAngle = ATAN2( -1.*DOT_PRODUCT( u%TurbineComponents%Hub%Orientation(3,:),         &
                                             u%TurbineComponents%RotorFurl%Orientation(2,:) ), &
                                DOT_PRODUCT( u%TurbineComponents%Hub%Orientation(3,:),         &
                                             u%TurbineComponents%RotorFurl%Orientation(3,:) )  ) + pi + (IBlade - 1)*p%TwoPiNB
      ! --- Loop on elements
      DO IElement = 1,p%Element%NElm

         SPitch    = SIN( m%Element%PitNow(IElement,IBlade) )
         CPitch    = COS( m%Element%PitNow(IElement,IBlade) )

            ! calculate distance between hub and element
         tmpVector = u%InputMarkers(IBlade)%Position(:,IElement) - u%TurbineComponents%Hub%Position(:)
         rLocal = SQRT(   DOT_PRODUCT( tmpVector, u%TurbineComponents%Hub%Orientation(2,:) )**2  &
                        + DOT_PRODUCT( tmpVector, u%TurbineComponents%Hub%Orientation(3,:) )**2  )

            ! determine if MulTabLoc should be set.

         IF (.not. p%Reynolds) m%AirFoil%MulTabLoc = u%MulTabLoc(IElement,IBlade)

         !-------------------------------------------------------------------------------------------
         ! Get wind velocity components; calculate velocity normal to the rotor squared
         ! Save variables for printing in a file later;
         !-------------------------------------------------------------------------------------------
         Node = Node + 1
         VelocityVec(:)    = AD_WindVelocityWithDisturbance( Time, u, p, x, xd, z, m, y, ErrStatLcl, ErrMessLcl, &
                                                             u%InputMarkers(IBlade)%Position(:,IElement), &
                                                             u%InflowVelocity(:,Node) )
            CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput' )
            IF (ErrStat >= AbortErrLev) THEN
               CALL CleanUp()
               RETURN
            END IF

         !-------------------------------------------------------------------------------------------
         ! DWM wind input update phase 1
         !-------------------------------------------------------------------------------------------
         IF (p%UseDWM) THEN
            !bjj: FIX THIS!!!!
            !bjj: where do p%DWM%RTPD%SimulationOrder_index and p%DWM%RTPD%upwindturbine_number get set?

            IF ( p%DWM%RTPD%SimulationOrder_index > 1) THEN
               IF(  p%DWM%RTPD%upwindturbine_number /= 0 ) THEN

                  m%DWM%position_y = u%InputMarkers(IBlade)%Position(2,IElement)

                  m%DWM%position_z = u%InputMarkers(IBlade)%Position(3,IElement)

                  m%DWM%velocity_wake_mean = 1

                  DO I = 1,p%DWM%RTPD%upwindturbine_number
                     m%DWM%DWM_tb%Aerodyn_turbine_num = I

                     CALL   DWM_phase1( Time, m%DWM_Inputs, p%DWM, x%DWM, xd%DWM, z%DWM, &
                                           O%DWM, m%DWM_Outputs, m%DWM, ErrStatLcl, ErrMessLcl )

                     CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput/DWM_phase1' )
                     IF (ErrStat >= AbortErrLev) THEN
                        CALL CleanUp()
                        RETURN
                     END IF

                     m%DWM%velocity_wake_mean = (1-((1-m%DWM%velocity_wake_mean)**2 + (1-m%DWM%shifted_velocity_aerodyn)**2)**0.5)
                  END DO

                  m%DWM%velocity_wake_mean    = m%DWM%velocity_wake_mean * p%DWM%Wind_file_Mean_u

                  VelocityVec(1) = (VelocityVec(1) - p%DWM%Wind_file_Mean_u)*(m%DWM_Inputs%Upwind_result%upwind_small_TI(1)/p%DWM%TI_amb) &
                                  + m%DWM%velocity_wake_mean

               END IF
            END IF

           !------------------------DWM PHASE 2-----------------------------------------------
            IF (Time > 50.00 ) THEN
               m%DWM%U_velocity           = VelocityVec(1)
               m%DWM%V_velocity           = VelocityVec(2)
               m%DWM%NacYaw               = m%Rotor%YawAng
               m%DWM%DWM_tb%Blade_index   = IBlade
               m%DWM%DWM_tb%Element_index = IElement

               CALL   DWM_phase2( Time, m%DWM_Inputs, p%DWM, x%DWM, xd%DWM, z%DWM, O%DWM, m%DWM_Outputs, m%DWM, ErrStatLcl, ErrMessLcl )

                     CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput/DWM_phase1' )
                     IF (ErrStat >= AbortErrLev) THEN
                        CALL CleanUp()
                        RETURN
                     END IF

               !CALL CalVelScale(VelocityVec(1),VelocityVec(2),m%DWM_Outputs,z%DWM)

               !CALL turbine_average_velocity( VelocityVec(1), IBlade, IElement, m%DWM_Outputs,x%DWM,z%DWM)
            END IF
         END IF ! UseDWM

         !-----------------------------------------------------------------------------------------------------------------------

         ! NOTE: VelocityVec is freestream with disturbances from Tower Shadow and Wakes (DWM)
         VelNormalToRotor2 = ( VelocityVec(3) * m%Rotor%STilt + (VelocityVec(1) * m%Rotor%CYaw               &
                             - VelocityVec(2) * m%Rotor%SYaw) * m%Rotor%CTilt )**2

         !-------------------------------------------------------------------------------------------
         ! Normal and tangential velocities from wind and relative blade motion
         !-------------------------------------------------------------------------------------------
         tang_Vector = - SPitch*u%InputMarkers(IBlade)%Orientation(1,:,IElement) &
                     & + CPitch*u%InputMarkers(IBlade)%Orientation(2,:,IElement)
         norm_Vector =   CPitch*u%InputMarkers(IBlade)%Orientation(1,:,IElement) &
                     & + SPitch*u%InputMarkers(IBlade)%Orientation(2,:,IElement)

         VTTotal   =   DOT_PRODUCT( tang_Vector, VelocityVec - u%InputMarkers(IBlade)%TranslationVel(:,IElement)  )
         VTElement = - DOT_PRODUCT( tang_Vector, u%InputMarkers(IBlade)%TranslationVel(:,IElement)  )
         VNElement = - DOT_PRODUCT( norm_Vector, u%InputMarkers(IBlade)%TranslationVel(:,IElement ) )

         VTWind    =   DOT_PRODUCT( tang_Vector, VelocityVec)
         VNWind    =   DOT_PRODUCT( norm_Vector, VelocityVec)

         !-------------------------------------------------------------------------------------------
         ! Get blade element forces and induced velocity
         !-------------------------------------------------------------------------------------------
         ! --------------------------------------------------------------------------------}
         ! --- Setting Element% values: W2, Alpha, A, AP
         ! --------------------------------------------------------------------------------{
         ! --- BEM
         CALL ELEM_INDUCTIONS( p, m, ErrStatLcl, ErrMessLcl,                             &
                    AzimuthAngle, rLocal, IElement, IBlade, VelNormalToRotor2, VTTotal, VNWind, &
                     VNElement, m%NoLoadsCalculated)
         ! Normal and tangential induced velocities
         VN_ind =  -  VNWind * m%Element%A (IElement, IBLADE)
         VT_ind =    VTTotal * m%Element%AP(IElement, IBLADE)

         ! Cumulative (integrated) induction over the blades
         m%InducedVel%SumInfl = m%InducedVel%SumInfl - VN_IND * RLOCAL * p%Blade%DR(IElement)

         !  --- Total flow velocity at the blade element
         VN = VN_IND + VNWind  + VNElement ! Normal velocity     : Indution +  Wind + Rel. blade vel
         VT = VT_IND + VTTotal             ! Tangential velocity : Indution + (Wind + Rel. blade vel)

         PHI   = ATAN2( VN, VT)                                                     ! Flow angle [rad]
         m%Element%ALPHA(IElement,IBlade) = PHI - m%Element%PitNow(IElement,IBlade) ! Angle of attack [rad]
         CALL MPI2PI ( m%Element%ALPHA(IElement,IBlade) )
         m%Element%W2(IElement,IBlade) = VN * VN + VT * VT                          ! Relative velocity norm

         CALL ELEMFRC2( p, m, ErrStatLcl, ErrMessLcl, IElement, IBlade, &
                     DFN, DFT, PMA, m%NoLoadsCalculated, phi )
            CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput' )
            IF (ErrStat >= AbortErrLev) THEN
               CALL CleanUp()
               RETURN
            END IF

         !-------------------------------------------------------------------------------------------
         ! Set up dynamic inflow parameters
         !-------------------------------------------------------------------------------------------
         IF ( p%DynInfl .OR. m%DynInit ) THEN
            CALL GetRM (P, m, ErrStatLcl, ErrMessLcl, &
                        rLocal, DFN, DFT, AzimuthAngle, IElement, IBlade)
               CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput' )
               IF (ErrStat >= AbortErrLev) THEN
                  CALL CleanUp()
                  RETURN
               END IF

         ENDIF

         IF (p%UseDWM) THEN
             m%DWM%Nforce(IElement,IBlade) = DFN              ! 12.4.2014 add by yh
         END IF ! UseDWM

         m%StoredForces(1,IElement,IBlade)  = ( DFN*CPitch + DFT*SPitch ) / p%Blade%DR(IElement)
         m%StoredForces(2,IElement,IBlade)  = ( DFN*SPitch - DFT*CPitch ) / p%Blade%DR(IElement)
         m%StoredForces(3,IElement,IBlade)  = 0.0

         m%StoredMoments(1,IElement,IBlade)  = 0.0
         m%StoredMoments(2,IElement,IBlade)  = 0.0
         m%StoredMoments(3,IElement,IBlade)  = PMA / p%Blade%DR(IElement)

!      DO IBlade=1,p%NumBl
!       DO IElement=1,p%Element%Nelm
!         y%OutputLoads(IBlade)%Force(:,IElement)  = m%StoredForces(:,IElement,IBlade)
!         y%OutputLoads(IBlade)%Moment(:,IElement) = m%StoredMoments(:,IElement,IBlade)
!       ENDDO
!!      ENDDO

            ! save velocities for output, if requested

         IF ( m%ElOut%WndElPrList(IElement) > 0 ) THEN
            m%ElOut%SaveVX( m%ElOut%WndElPrList(IElement), IBlade ) = VelocityVec(1)
            m%ElOut%SaveVY( m%ElOut%WndElPrList(IElement), IBlade ) = VelocityVec(2)
            m%ElOut%SaveVZ( m%ElOut%WndElPrList(IElement), IBlade ) = VelocityVec(3)
         ENDIF

      END DO !IElement

      IF ( IBlade == 1 .AND. p%ElemPrn ) THEN
         m%ElOut%VXSAV  = VelocityVec(1)
         m%ElOut%VYSAV  = VelocityVec(2)
         m%ElOut%VZSAV  = VelocityVec(3)
      ENDIF

   END DO !IBlade

   m%NoLoadsCalculated = .FALSE.

   DO IBlade=1,p%NumBl
     DO IElement=1,p%Element%Nelm
       y%OutputLoads(IBlade)%Force(:,IElement)  = m%StoredForces(:,IElement,IBlade)
       y%OutputLoads(IBlade)%Moment(:,IElement) = m%StoredMoments(:,IElement,IBlade)
     ENDDO
   ENDDO

   !------------------------DWM PHASE 3-----------------------------------------------
   IF (p%UseDWM) THEN

      IF (Time > 50.00 ) THEN !BJJ: why is 50 hard-coded here and above???

         !m%DWM%Nforce(:,:)    = m%DWM%DFN_DWM(:,:)
         CALL   DWM_phase3( Time, m%DWM_Inputs, p%DWM, x%DWM, xd%DWM, z%DWM, O%DWM, m%DWM_Outputs, m%DWM, ErrStatLcl, ErrMessLcl )

            CALL SetErrStat ( ErrStatLcl, ErrMessLcl, ErrStat,ErrMess,'AD14_CalcOutput/DWM_phase3' )
            IF (ErrStat >= AbortErrLev) THEN
               CALL CleanUp()
               RETURN
            END IF

         !CALL filter_average_induction_factor( AD14_ParameterType, DWM_ConstraintStateType, m%DWM_Outputs )
      END IF
   END IF !UseDWM

   !-----------------------------------------------------------------------------------

      ! Loop through all the tower nodes to calculate the aerodynamic loads on the tower if aerodynamics were requested.

   IF ( p%TwrProps%CalcTwrAero )  THEN

      DO Node=1,u%Twr_InputMarkers%Nnodes

            ! Calculate the aerodynamic load on this tower node: TwrAeroLoads ( p, Node, NodeDCMGbl, NodeVelGbl, NodeWindVelGbl, NodeFrcGbl )

         CALL TwrAeroLoads ( p, Node, u%Twr_InputMarkers%Orientation(:,:,Node), u%Twr_InputMarkers%TranslationVel(:,Node) &
                           , u%InflowVelocity(:,Node+p%NumBl*p%Element%NElm), y%Twr_OutputLoads%Force(:,Node) )

      END DO ! Node

   END IF ! ( p%TwrProps%CalcTwrAero )

   !................................................................................................

   CALL ElemOut(time, P, m )

   CALL CleanUp (  )

   RETURN

   !=======================================================================
   CONTAINS
   !=======================================================================
   SUBROUTINE CleanUp ( )

      ! This subroutine cleans up the parent routine before exiting.

      !   ! Deallocate the IfW_Inputs%Position array if it had been allocated.
      !
      !CALL IfW_DestroyInput( IfW_Inputs, ErrStatLcl, ErrMessLcl )

      RETURN

   END SUBROUTINE CleanUp

END SUBROUTINE AD14_CalcOutput

!----------------------------------------------------------------------------------------------------------------------------------
END MODULE AeroDyn14
!**********************************************************************************************************************************