XBeach
C:/repositories/XBeach/trunk/src/xbeachlibrary/wave_boundary_update.f90
Go to the documentation of this file.
00001 module wave_boundary_update_module
00002    use wave_boundary_datastore
00003    !
00004    implicit none
00005    save
00006    private
00007    public generate_wave_boundary_surfbeat
00008    !
00009    type spectrum                                         ! These are related to input spectra
00010       real*8,dimension(:,:),pointer          :: S        ! 2D variance density spectrum
00011       real*8,dimension(:),pointer            :: f,ang    ! 1D frequency and direction vectors for S
00012       real*8,dimension(:),pointer            :: Sf       ! S integrated over all directions
00013       integer                                :: nf,nang  ! number of frequencies and angles
00014       real*8                                 :: df,dang  ! frequency and angle step size
00015       real*8                                 :: hm0,fp,dir0,scoeff  ! imposed significant wave height, peak frequency,
00016       ! main wave angle and spreading coefficient
00017       real*8                                 :: trep,dirm ! representative period and mean wave direction
00018    endtype spectrum
00019    type shortspectrum
00020       real*8,dimension(:),pointer            :: Sf         ! S integrated over all directions
00021    endtype shortspectrum
00022    type waveparamsnew                                      ! These are related to the generated bc series
00023       real*8                                 :: h0         ! average water depth on offshore boundary
00024       integer                                :: K          ! number of wave train components
00025       real*8                                 :: rtbc,dtbc  ! duration and time step to be written to boundary condition file
00026       real*8                                 :: rtin,dtin  ! duration and time step for the internal time axis, based on Fourier
00027       ! limitations and the number of wave train components (wp%K)
00028       real*8,dimension(:),pointer            :: tin        ! internal time axis
00029       real*8,dimension(:),pointer            :: taperf,taperw  ! internal taper function for flow and waves
00030       integer                                :: tslen      ! internal time axis length (is always even, not odd)
00031       integer                                :: tslenbc    ! time axis length for boundary condition file
00032       logical                                :: dtchanged  ! quick check to see if dtin == dtbc (useful for interpolation purpose)
00033       real*8,dimension(:),pointer            :: fgen,thetagen,phigen,kgen,wgen ! frequency, angle, phase, wave number, radian frequency
00034       ! of wavetrain components for boundary signal
00035       real*8                                 :: dfgen      ! frequency grid size in the generated components
00036       type(shortspectrum),dimension(:),pointer :: vargen   ! This is where the variance for each wave train at each spectrum location
00037       ! is stored
00038       type(shortspectrum),dimension(:),pointer :: vargenq  ! This is where the variance for each wave train at each spectrum location
00039       ! is stored, which is not scaled and is used for the generation of bound waves
00040       real*8,dimension(:,:),pointer          :: A          ! Amplitude, per wave train component, per offshore grid point A(ny+1,K)
00041       real*8,dimension(:,:),pointer          :: Sfinterp   ! S integrated over all directions at frequency locations of fgen,
00042       ! per offshore grid point Sfinterp(ny+1,K)
00043       real*8,dimension(:,:),pointer          :: Sfinterpq  ! S integrated over all directions at frequency locations of fgen,
00044       ! per offshore grid point Sfinterpq(ny+1,K), uncorrected for generation of bound waves
00045       real*8,dimension(:),pointer            :: Hm0interp  ! Hm0 per offshore point, based on intergration of Sfinterp and used to scale
00046       ! final time series
00047       integer, dimension(:),pointer          :: Findex     ! Index of wave train component locations on frequency/Fourier axis
00048       integer, dimension(:),pointer          :: WDindex    ! Index of wave train component locations on wave directional bin axis
00049       double complex,dimension(:,:),pointer  :: CompFn     ! Fourier components of the wave trains
00050       character(1024)                        :: Efilename,qfilename,nhfilename
00051       real*8,dimension(:,:),pointer          :: zsits      ! time series of total surface elevation for nonhspectrum==1
00052       real*8,dimension(:,:),pointer          :: uits       ! time series of depth-averaged horizontal velocity nonhspectrum==1
00053       real*8,dimension(:,:),pointer          :: wits       ! time series of depth-averaged vertical velocity for nonhspectrum==1  ??
00054    endtype waveparamsnew
00055    !
00056    ! These parameters control a lot how the spectra are handled. They could be put in params.txt,
00057    ! but most users will want to keep these at their default values anyway
00058    integer,parameter                         :: nfint = 801   ! size of standard 2D spectrum in frequency dimension
00059    integer,parameter                         :: naint = 401   ! size of standard 2D spectrum in angular dimension
00060    integer,parameter                         :: Kmin  = 200   ! minimum number of wave train components
00061    real*8,parameter                          :: wdmax = 5.d0  ! maximum depth*reliable angular wave frequency that can be resolved by
00062    ! nonhydrostatic wave model. All frequencies above this are removed
00063    ! from nonhspectrum generation
00064    ! Shortcut pointers to commonly used parameters
00065    integer                                   :: nspectra,bccount,npb
00066    real*8                                    :: hb0
00067    ! Physical constants
00068    real*8,parameter                          :: par_pi = 4.d0*atan(1.d0)
00069    real*8,parameter                          :: par_g  = 9.81d0
00070    complex(kind(0.0d0)),parameter            :: par_compi = (0.0d0,1.0d0)
00071 contains
00072 
00073    subroutine generate_wave_boundary_surfbeat(durationlength)
00074 #ifdef BUILDXBEACH
00075       use logging_module
00076 #endif
00077       use wave_boundary_datastore
00078       implicit none
00079       ! Input and output variables
00080       real*8,intent(out)          :: durationlength
00081       !
00082       !
00083       ! Internal variables
00084       type(spectrum),dimension(:),allocatable         :: specin,specinterp
00085       type(spectrum)              :: combspec
00086       type(waveparamsnew)         :: wp             ! Most will be deallocated, but some variables useful to keep?
00087       integer                     :: iloc
00088       integer                     :: iostat
00089       real*8                      :: spectrumendtimeold,fmax
00090 
00091       ! Shortcuts, could be pointers?
00092       nspectra = waveSpectrumAdministration%nspectra
00093       bccount  = waveSpectrumAdministration%bccount
00094       ! Offshore water depth, which is used in various computations in this module
00095       hb0 = waveBoundaryParameters%hboundary
00096       npb = waveBoundaryParameters%np
00097       !
00098       !
00099       ! Start Wave boundary condition time series generation
00100       if (waveSpectrumAdministration%repeatwbc) then
00101          ! Return wave boundary conditions that have already been computed in a previous
00102          ! call to this subroutine. Modify time axis to reflect shift in time since the
00103          ! previous call
00104          waveBoundaryTimeSeries%tbc = min(waveBoundaryTimeSeries%tbc, &
00105          huge(0.d0)-waveBoundaryAdministration%startComputeNewSeries) + &
00106          waveBoundaryAdministration%startComputeNewSeries
00107 
00108       else
00109 #ifdef BUILDXBEACH
00110          call writelog('l','','--------------------------------')
00111          call writelog('ls','','Calculating spectral wave boundary conditions ')
00112          call writelog('l','','--------------------------------')
00113 #endif
00114          ! allocate temporary input storage
00115          if (.not. allocated(specin)) then
00116             allocate(specin(nspectra))
00117             allocate(specinterp(nspectra))
00118          endif
00119 
00120          ! Read through input spectra files
00121          fmax = 1.d0   ! assume 1Hz as maximum frequency. Increase in loop below if needed.
00122          do iloc = 1,nspectra
00123 #ifdef BUILDXBEACH
00124             call writelog('sl','(a,i0)','Reading spectrum at location ',iloc)
00125 #endif
00126             ! Read input file
00127             call read_spectrum_input(wp,bcfiles(iloc),specin(iloc))
00128             fmax = max(fmax,maxval(specin(iloc)%f))
00129          enddo
00130          do iloc = 1,nspectra
00131 #ifdef BUILDXBEACH
00132             call writelog('sl','(a,i0)','Interpreting spectrum at location ',iloc)
00133 #endif
00134             ! Interpolate input 2D spectrum to standard 2D spectrum
00135             call interpolate_spectrum(specin(iloc),specinterp(iloc),par,fmax)
00136 #ifdef BUILDXBEACH
00137             call writelog('sl','','Values calculated from interpolated spectrum:')
00138             call writelog('sl','(a,f0.2,a)','Hm0       = ',specinterp(iloc)%hm0,' m')
00139             call writelog('sl','(a,f0.2,a)','Trep      = ',specinterp(iloc)%trep,' s')
00140             call writelog('sl','(a,f0.2,a)','Mean dir  = ',specinterp(iloc)%dirm,' degN')
00141 #endif
00142          enddo
00143 
00144          ! Determine whether all the spectra are to be reused, which implies that the global repeatwbc should be
00145          ! set to true (no further computations required in future calls)
00146          call set_repeatwbc
00147          !
00148          ! calculate the mean combined spectra (used for combined Trep, determination of wave components, etc.)
00149          ! now still uses simple averaging, but could be improved to use weighting for distance etc.
00150          call generate_combined_spectrum(specinterp,combspec)
00151          ! Store these data in wave administration for exchange with outer
00152          ! XBeach or D3D/FM models
00153          waveSpectrumAdministration%Hbc = combspec%hm0
00154          waveSpectrumAdministration%Tbc = combspec%trep
00155          waveSpectrumAdministration%Dbc = combspec%dirm
00156 #ifdef BUILDXBEACH
00157          call writelog('sl','(a,f0.2,a)','Overall Trep from all spectra calculated: ',&
00158          waveSpectrumAdministration%Tbc,' s')
00159 #endif
00160          ! Wave trains that are used by XBeach. The number of wave trains, their frequencies and directions
00161          ! are based on the combined spectra of all the locations to ensure all wave conditions are
00162          ! represented in the XBeach model
00163          call generate_wavetrain_components(combspec,wp)
00164 
00165          ! We can now apply a correction to the wave train components if necessary. This section can be
00166          ! improved later
00167          if (nspectra==1 .and. specin(1)%scoeff>1000.d0) then
00168             ! this can be used both for Jonswap and vardens input
00169             wp%thetagen = mod(specin(1)%dir0,2*par_pi)
00170          endif
00171 
00172          ! Set up time axis, including the time axis for output to boundary condition files and an
00173          ! internal time axis, which may differ in length to the output time axis
00174          call generate_wave_time_axis(wp)
00175 
00176          ! Determine the variance for each wave train component, at every spectrum location point
00177          call generate_wave_train_variance(wp,specinterp)
00178 
00179          ! Determine the amplitude of each wave train component, at every point along the
00180          ! offshore boundary
00181          call generate_wave_train_properties_per_offshore_point(wp,s)
00182 
00183          ! Generate Fourier components for all wave train component, at every point along
00184          ! the offshore boundary
00185          call generate_wave_train_Fourier(wp)
00186 
00187          ! Time series of short wave energy or surface elevation
00188          ! Distribute all wave train components among the wave direction bins. Also rearrage
00189          ! the randomly drawn wave directions to match the centres of the wave bins if the
00190          ! user-defined nspr is set on.
00191          call distribute_wave_train_directions(wp,waveBoundaryParameters%nspr)
00192          if (.not.waveBoundaryParameters%nonhspectrum) then
00193             ! Calculate the wave energy envelope per offshore grid point and write to output file
00194             call generate_ebcf(wp)
00195          else
00196             ! Generate time series of surface elevation, horizontal velocity and vertical velocity
00197             call generate_swts(wp,s)
00198          endif
00199 
00200          ! Calculate the bound long wave from the wave train components and write to output file
00201          call generate_qbcf(wp)
00202 
00203          ! Write non-hydrostatic time series of combined short and long waves if necessary
00204          if (waveBoundaryParameters%nonhspectrum) then
00205             call generate_nhtimeseries_file(wp)
00206          endif
00207 
00208          ! Deallocate a lot of memory
00209          deallocate(specin,specinterp)
00210          deallocate(wp%tin,wp%taperf,wp%taperw)
00211          deallocate(wp%fgen,wp%thetagen,wp%phigen,wp%kgen,wp%wgen)
00212          deallocate(wp%vargen)
00213          deallocate(wp%vargenq)
00214          deallocate(wp%Sfinterp)
00215          deallocate(wp%Sfinterpq)
00216          deallocate(wp%Hm0interp)
00217          deallocate(wp%A)
00218          deallocate(wp%Findex)
00219          deallocate(wp%CompFn)
00220          if (waveBoundaryParameters%nonhspectrum) then
00221             deallocate(wp%zsits)
00222             deallocate(wp%uits)
00223          else
00224             deallocate(wp%WDindex)
00225          endif
00226          ! Send message to screen and log
00227 #if BUILDXBEACH
00228          call writelog('l','','--------------------------------')
00229          call writelog('ls','','Spectral wave boundary conditions complete ')
00230          call writelog('l','','--------------------------------')
00231 #endif
00232       endif ! repeatwbc
00233       !
00234       ! Return the duration length of the current boundary conditions
00235       durantionlength = wp%rtbc
00236       !
00237       ! Update the number of boundary conditions generated by this module
00238       bccount = bccount+1
00239 
00240    endif
00241 
00242 endsubroutine generate_wave_boundary_surfbeat
00243 
00244 ! --------------------------------------------------------------
00245 ! ---------------- Read input spectra files --------------------
00246 ! --------------------------------------------------------------
00247 subroutine read_spectrum_input(wp,fn,specin)
00248 
00249    use filefunctions
00250    use logging_module
00251 
00252    implicit none
00253    ! Interface
00254    type(waveparamsnew),intent(inout) :: wp
00255    type(filenames),intent(inout)  :: fn
00256    type(spectrum),intent(inout)   :: specin
00257    ! internal
00258    integer                     :: fid
00259    character(8)                :: testline
00260    character(1024)             :: readfile
00261    logical                     :: filelist
00262    integer                     :: i,ier
00263 
00264    ! check the first line of the boundary condition file for FILELIST keyword
00265    fid = create_new_fid()
00266    open(fid,file=fn%fname,status='old',form='formatted')
00267    read(fid,*,iostat=ier)testline
00268    if (ier .ne. 0) then
00269       call report_file_read_error(fn%fname)
00270    endif
00271    if (trim(testline)=='FILELIST') then
00272       filelist = .true.
00273       ! move listline off its default position of zero to the first row
00274       if (fn%listline==0) then
00275          fn%listline = 1
00276       endif
00277       fn%repeat = .false.
00278    else
00279       filelist = .false.
00280       if (par%instat /= INSTAT_JONS_TABLE) then
00281          fn%repeat = .true.
00282       else
00283          fn%repeat = .false.
00284       endif
00285    endif
00286    close(fid)
00287    ! If file has list of spectra, read through the lines to find the correct
00288    ! spectrum file name and rtbc and dtbc. Else the filename and rtbc, dtbc are in
00289    ! params.txt
00290    if (filelist) then
00291       fid = create_new_fid()
00292       open(fid,file=fn%fname,status='old',form='formatted')
00293       do i=1,fn%listline
00294          read(fid,*)testline  ! old stuff, not needed anymore
00295       enddo
00296       read(fid,*,iostat=ier)wp%rtbc,wp%dtbc,readfile  ! new boundary condition
00297       if (ier .ne. 0) then
00298          call report_file_read_error(fn%fname)
00299       endif
00300       ! we have to adjust this to morphological time, as done in params.txt
00301       if (par%morfacopt==1) then
00302          wp%rtbc = wp%rtbc/max(par%morfac,1.d0)
00303       endif
00304       fn%listline = fn%listline + 1   ! move one on from the last time we opened this file
00305       close(fid)
00306    else
00307       wp%rtbc = par%rt  ! already set to morphological time
00308       wp%dtbc = par%dtbc
00309       readfile = fn%fname
00310    endif
00311 
00312    ! based on the value of instat, we need to read either Jonswap, Swan or vardens files
00313    ! note: jons_table is also handeled by read_jonswap_file subroutine
00314    !select case (par%instat(1:4))
00315    select case(par%instat)
00316       !case ('jons')
00317     case (INSTAT_JONS, INSTAT_JONS_TABLE)
00318       ! wp type sent in to receive rtbc and dtbc from jons_table file
00319       ! fn%listline sent in to find correct row in jons_table file
00320       ! pfff..
00321       call read_jonswap_file(par,wp,readfile,fn%listline,specin)
00322       !case ('swan')
00323     case (INSTAT_SWAN)
00324       call read_swan_file(par,readfile,specin)
00325       !case ('vard')
00326     case (INSTAT_VARDENS)
00327       call read_vardens_file(par,readfile,specin)
00328    endselect
00329 
00330 endsubroutine read_spectrum_input
00331 
00332 ! --------------------------------------------------------------
00333 ! ------------------- Read JONSWAP files -----------------------
00334 ! --------------------------------------------------------------
00335 subroutine read_jonswap_file(par,wp,readfile,listline,specin)
00336 
00337    use readkey_module
00338    use params
00339    use logging_module
00340    use filefunctions
00341 
00342    IMPLICIT NONE
00343 
00344    ! Input / output variables
00345    type(parameters), INTENT(IN)            :: par
00346    type(waveparamsnew),intent(inout)       :: wp
00347    character(len=*), intent(IN)            :: readfile
00348    integer, intent(INOUT)                  :: listline
00349    type(spectrum),intent(inout)            :: specin
00350 
00351    ! Internal variables
00352    integer                                 :: i,ii,ier,ip,ind
00353    integer                                 :: nmodal
00354    integer                                 :: fid
00355    integer                                 :: forcepartition
00356    integer,dimension(2)                    :: indvec
00357    real*8,dimension(:),allocatable         :: x, y, Dd, tempdir
00358    real*8,dimension(:),allocatable         :: Hm0,fp,gam,mainang,scoeff
00359    real*8                                  :: dfj, fnyq
00360    real*8                                  :: Tp
00361    character(len=80)                       :: dummystring
00362    type(spectrum),dimension(:),allocatable :: multinomalspec,scaledspec
00363    logical                                 :: cont
00364    real*8,dimension(:),allocatable         :: scalefac1,scalefac2,tempmax,avgscale
00365    real*8,dimension(:),allocatable         :: oldvariance,newvariance
00366    real*8                                  :: newconv,oldconv
00367 
00368    ! First part: read JONSWAP parameter data
00369 
00370    ! Check whether spectrum characteristics or table should be used
00371    if (par%instat /= INSTAT_JONS_TABLE) then
00372       ! Use spectrum characteristics
00373       call writelog('sl','','waveparams: Reading from ',trim(readfile),' ...')
00374       !
00375       ! First read if the spectrum is multinodal, and how many peaks there should be
00376       !
00377       nmodal     = readkey_int (readfile, 'nmodal',  1,  1, 4, bcast=.false.)
00378       if (nmodal<1) then
00379          call writelog('lswe','','Error: number of spectral partions may not be less than 1 in ',trim(readfile))
00380          call halt_program
00381       endif
00382       !
00383       ! Allocate space for all spectral parameters
00384       !
00385       allocate(Hm0(nmodal))
00386       allocate(fp(nmodal))
00387       allocate(gam(nmodal))
00388       allocate(mainang(nmodal))
00389       allocate(scoeff(nmodal))
00390       !
00391       ! Read the spectral parameters for all spectrum components
00392       !
00393       ! Wave height (required)
00394       Hm0    = readkey_dblvec(readfile, 'Hm0',nmodal,nmodal, 0.0d0, 0.0d0, 5.0d0, bcast=.false.,required=.true. )
00395       !
00396       ! Wave period (required)
00397       ! allow both Tp and fp specification to bring in line with params.txt
00398       if (isSetParameter(readfile,'Tp',bcast=.false.) .and. .not. isSetParameter(readfile,'fp',bcast=.false.)) then
00399          fp     = 1.d0/readkey_dblvec(readfile, 'Tp',nmodal,nmodal, 12.5d0, 2.5d0, 20.0d0, bcast=.false.)
00400       elseif (isSetParameter(readfile,'fp',bcast=.false.) .and. .not. isSetParameter(readfile,'Tp',bcast=.false.)) then
00401          fp     = readkey_dblvec(readfile, 'fp',nmodal,nmodal, 0.08d0,0.0625d0,   0.4d0, bcast=.false.)
00402       elseif (.not. isSetParameter(readfile,'fp',bcast=.false.) .and. .not. isSetParameter(readfile,'Tp',bcast=.false.)) then
00403          call writelog('lswe','','Error: missing required value for parameter ''Tp'' or ''fp'' in ',trim(readfile))
00404          call halt_program
00405       else
00406          fp     = 1.d0/readkey_dblvec(readfile, 'Tp',nmodal,nmodal, 12.5d0, 2.5d0, 20.0d0, bcast=.false.)
00407          call writelog('lsw','','Warning: selecting to read peak period (Tp) instead of frequency (fp) in ',trim(readfile))
00408       endif
00409       !
00410       ! Wave spreading in frequency domain (peakedness)
00411       !
00412       gam    = readkey_dblvec(readfile, 'gammajsp',nmodal,nmodal, 3.3d0, 1.0d0, 5.0d0, bcast=.false.)
00413       !
00414       ! Wave spreading in directional domain
00415       !
00416       scoeff = readkey_dblvec(readfile, 's',nmodal,nmodal, 10.0d0, 1.0d0, 1000.0d0, bcast=.false.)
00417       !
00418       ! Main wave direction
00419       ! allow both mainang and dir0 specification to bring in line with params.txt
00420       if (isSetParameter(readfile,'mainang',bcast=.false.) .and. &
00421       .not. isSetParameter(readfile,'dir0',bcast=.false.)) then
00422          mainang = readkey_dblvec(readfile, 'mainang',nmodal,nmodal, &
00423          270.0d0, 0.0d0, 360.0d0, bcast=.false.)
00424       elseif (isSetParameter(readfile,'dir0',bcast=.false.) .and. &
00425       .not. isSetParameter(readfile,'mainang',bcast=.false.)) then
00426          mainang = readkey_dblvec(readfile, 'dir0',nmodal,nmodal, &
00427          270.0d0, 0.0d0, 360.0d0, bcast=.false.)
00428       elseif (.not. isSetParameter(readfile,'dir0',bcast=.false.) .and. &
00429       .not. isSetParameter(readfile,'mainang',bcast=.false.)) then
00430          mainang = 270.d0
00431       else
00432          mainang = readkey_dblvec(readfile, 'mainang',nmodal,nmodal, 270.0d0, 0.0d0, 360.0d0, bcast=.false.)
00433          call writelog('lsw','','Warning: selecting to read ''mainang'' instead of ''dir0'' in ',trim(readfile))
00434       endif
00435       !
00436       ! Nyquist parameters used only in this subroutine
00437       ! are not read individually for each spectrum partition
00438       if (par%oldnyq==1) then
00439          fnyq    = readkey_dbl (readfile, 'fnyq',       0.3d0,    0.2d0,      1.0d0,      bcast=.false. )
00440       else
00441          fnyq    = readkey_dbl (readfile, 'fnyq',max(0.3d0,3.d0*maxval(fp)), 0.2d0, 1.0d0, bcast=.false. )
00442       endif
00443       dfj        = readkey_dbl (readfile, 'dfj',      fnyq/200,   fnyq/1000,  fnyq/20,    bcast=.false. )
00444       !
00445       ! Finally check if XBeach should accept even the most stupid partioning (sets error level to warning
00446       ! level when computing partition overlap
00447       if (nmodal>1) then
00448          forcepartition = readkey_int (readfile, 'forcepartition',  0,  0, 1, bcast=.false.)
00449       endif
00450       ! check for other strange values in this file
00451       call readkey(readfile,'checkparams',dummystring)
00452    else
00453       nmodal = 1
00454       allocate(Hm0(nmodal))
00455       allocate(fp(nmodal))
00456       allocate(gam(nmodal))
00457       allocate(mainang(nmodal))
00458       allocate(scoeff(nmodal))
00459       ! Use spectrum table
00460       fid = create_new_fid()
00461       call writelog('sl','','waveparams: Reading from table ',trim(readfile),' ...')
00462       open(fid,file=readfile,status='old',form='formatted')
00463       ! read junk up to the correct line in the file
00464       do i=1,listline
00465          read(fid,*,iostat=ier)dummystring
00466          if (ier .ne. 0) then
00467             call report_file_read_error(readfile)
00468          endif
00469       enddo
00470       read(fid,*,iostat=ier)Hm0(1),Tp,mainang(1),gam(1),scoeff(1),wp%rtbc,wp%dtbc
00471       if (ier .ne. 0) then
00472          call writelog('lswe','','Error reading file ',trim(readfile))
00473          close(fid)
00474          call halt_program
00475       endif
00476       ! move the line pointer in the file
00477       listline = listline+1
00478       ! convert to morphological time
00479       if (par%morfacopt==1) then
00480          wp%rtbc = wp%rtbc/max(par%morfac,1.d0)
00481       endif
00482       fp(1)=1.d0/Tp
00483       fnyq=3.d0*fp(1)
00484       dfj=fp(1)/50
00485       close(fid)
00486    endif
00487    !
00488    ! Second part: generate 2D spectrum from input parameters
00489    !
00490    ! Define number of frequency bins by defining an array of the necessary length
00491    ! using the Nyquist frequency and frequency step size
00492    specin%nf = ceiling((fnyq-dfj)/dfj)
00493    specin%df = dfj
00494    !
00495    ! Define array with actual eqidistant frequency bins
00496    allocate(specin%f(specin%nf))
00497    do i=1,specin%nf
00498       specin%f(i)=i*dfj
00499    enddo
00500    !
00501    ! we need a normalised frequency and variance vector for JONSWAP generation
00502    allocate(x(size(specin%f)))
00503    allocate(y(size(specin%f)))
00504    !
00505    ! Define 200 directions relative to main angle running from 0 to 2*pi
00506    ! we also need a temporary vector for direction distribution
00507    specin%nang = naint
00508    allocate(tempdir(specin%nang))
00509    allocate(Dd(specin%nang))
00510    allocate(specin%ang(specin%nang))
00511    specin%dang = 2*par_pi/(naint-1)
00512    do i=1,specin%nang
00513       specin%ang(i)=(i-1)*specin%dang
00514    enddo
00515    !
00516    ! Generate density spectrum for each spectrum partition
00517    !
00518    allocate(multinomalspec(nmodal))
00519    !
00520    do ip=1,nmodal
00521       ! relative frequenct vector
00522       x=specin%f/fp(ip)
00523       ! Calculate unscaled and non-directional JONSWAP spectrum using
00524       ! peak-enhancement factor and pre-determined frequency bins
00525       call jonswapgk(x,gam(ip),y)
00526       ! Determine scaled and non-directional JONSWAP spectrum using the JONSWAP
00527       ! characteristics
00528       y=(Hm0(ip)/(4.d0*sqrt(sum(y)*dfj)))**2*y
00529       ! Convert main angle from degrees to radians and from nautical convention to
00530       ! internal grid
00531       mainang(ip)=(1.5d0*par_pi)-mainang(ip)*par_pi/180
00532       ! Make sure the main angle is defined between 0 and 2*pi
00533       do while (mainang(ip)>2*par_pi .or. mainang(ip)<0.d0) !Robert en Ap
00534          if (mainang(ip)>2*par_pi) then
00535             mainang(ip)=mainang(ip)-2*par_pi
00536          elseif (mainang(ip)<0.d0) then
00537             mainang(ip)=mainang(ip)+2*par_pi
00538          endif
00539       enddo
00540       ! Convert 200 directions relative to main angle to directions relative to
00541       ! internal grid
00542       ! Bas: apparently division by 2 for cosine law happens already here
00543       tempdir = (specin%ang-mainang(ip))/2
00544       ! Make sure all directions around the main angle are defined between 0 and 2*pi
00545       do while (any(tempdir>2*par_pi) .or. any(tempdir<0.d0))
00546          where (tempdir>2*par_pi)
00547             tempdir=tempdir-2*par_pi
00548          elsewhere (tempdir<0.d0)
00549             tempdir=tempdir+2*par_pi
00550          endwhere
00551       enddo
00552       ! Calculate directional spreading based on cosine law
00553       Dd = dcos(tempdir)**(2*nint(scoeff(ip)))  ! Robert: apparently nint is needed here, else MATH error
00554       ! Scale directional spreading to have a surface of unity by dividing by its
00555       ! own surface
00556       Dd = Dd / (sum(Dd)*specin%dang)
00557       ! Define two-dimensional variance density spectrum array and distribute
00558       ! variance density for each frequency over directional bins
00559       allocate(multinomalspec(ip)%S(specin%nf,specin%nang))
00560       do i=1,specin%nang
00561          do ii=1,specin%nf
00562             multinomalspec(ip)%S(ii,i)=y(ii)*Dd(i)
00563          end do
00564       end do
00565    enddo  ! 1,nmodal
00566    do ip=1,nmodal
00567       write(*,*)'Hm0 = ',4*sqrt(sum(multinomalspec(ip)%S)*specin%dang*specin%df)
00568    enddo
00569    !
00570    ! Combine spectrum partitions so that the total spectrum is correct
00571    !
00572    if (nmodal==1) then
00573       ! Set all the useful parameters and arrays
00574       specin%Hm0 = Hm0(1)
00575       specin%fp = fp(1)
00576       specin%dir0 = mainang(1)
00577       specin%scoeff = scoeff(1)
00578       allocate(specin%S(specin%nf,specin%nang))
00579       specin%S = multinomalspec(1)%S
00580    else
00581       specin%Hm0 = sqrt(sum(Hm0**2))  ! total wave height
00582       ind = maxval(maxloc(Hm0))       ! spectrum that is largest
00583       specin%fp = fp(ind)             ! not really used in further calculation
00584       specin%dir0 = mainang(ind)      ! again not really used in further calculation
00585       ! if all scoeff>1000 then all waves should be in the same direction exactly
00586       if (all(scoeff>=1024.d0) .and. all(mainang==mainang(ind))) then
00587          specin%scoeff = 1024.d0
00588       else
00589          specin%scoeff = min(scoeff(ind),999.d0)
00590       endif
00591       ! Now we have to loop over all partitioned spectra. Where two or more spectra
00592       ! overlap, only the largest is counted, and all others are set to zero. Afterwards
00593       ! all spectra are scaled so that the total energy is maintained. Since the scaling
00594       ! affects where spectra overlap, this loop is repeated until only minor changes
00595       ! in the scaling occur. Warnings or errors are given if the spectrum is scaled too
00596       ! much, i.e. spectra overlap too much.
00597       !
00598       ! Allocate space
00599       allocate(scaledspec(nmodal)) ! used to store scaled density spectra
00600       do ip=1,nmodal
00601          allocate(scaledspec(ip)%S(specin%nf,specin%nang))
00602          scaledspec(ip)%S = multinomalspec(ip)%S
00603       enddo
00604       allocate(scalefac1(nmodal))  ! this is the scaling factor required to maintain Hm0
00605       ! including that parts of the spectrum are set to zero
00606       scalefac1 = 1.d0
00607       allocate(scalefac2(nmodal))  ! this is the scaling factor required to maintain Hm0
00608       ! in the previous iteration
00609       scalefac2 = 1.d0
00610       allocate(avgscale(nmodal))
00611       avgscale = 1.d0
00612       ! these are convergence criteria
00613       newconv = 0.d0
00614       oldconv = huge(0.d0)
00615       cont = .true.
00616       allocate(tempmax(nmodal))     ! used to store maximum value in f,theta space
00617       allocate(oldvariance(nmodal)) ! used to store the sum of variance in the original partitions
00618       do ip=1,nmodal
00619          oldvariance(ip) = sum(multinomalspec(ip)%S)
00620       enddo
00621       allocate(newvariance(nmodal)) ! used to store the sum of variance in the new partitions
00622       !
00623       ! Start convergence loop
00624       do while (cont)
00625          avgscale = (avgscale+scalefac1)/2
00626          ! First scale the spectra
00627          do ip=1,nmodal
00628             ! scale the spectrum using less than half the additional scale factor, this to
00629             ! ensure the method does not become unstable
00630             ! scaledspec(ip)%S = multinomalspec(ip)%S*(0.51d0+scalefac1(ip)*0.49d0)
00631             ! scaledspec(ip)%S = multinomalspec(ip)%S*(scalefac1(ip)+scalefac2(ip))/2
00632             scaledspec(ip)%S = multinomalspec(ip)%S*avgscale(ip)
00633 
00634          enddo
00635          do i=1,specin%nang
00636             do ii=1,specin%nf
00637                ! vector of variance densities at this point in f,theta space
00638                do ip=1,nmodal
00639                   tempmax(ip) = scaledspec(ip)%S(ii,i)
00640                end do
00641                ! All spectra other than the one that is greatest in this point
00642                ! is set to zero. In case multiple spectra are equal largest,
00643                ! the first spectrum in the list is chosen (minval(maxloc))
00644                ind = minval(maxloc(tempmax))
00645                do ip=1,nmodal
00646                   if (ip/=ind) then
00647                      scaledspec(ip)%S(ii,i) = 0.d0
00648                   endif
00649                enddo
00650             enddo
00651          end do
00652          !
00653          ! Now rescale adjusted partition spectra so that they match the incident Hm0
00654          scalefac2 = scalefac1  ! keep previous results
00655          do ip=1,nmodal
00656             newvariance(ip) = sum(scaledspec(ip)%S)
00657             if (newvariance(ip)>0.01d0*oldvariance(ip)) then
00658                scalefac1(ip) = oldvariance(ip)/newvariance(ip) ! want to maximise to a factor 2
00659                ! else can generate rediculous results
00660             else
00661                scalefac1(ip) = 0.d0                            ! completely remove this spectrum
00662             endif
00663          enddo
00664          !
00665          ! check convergence criteria (if error is increasing, we have passed best fit)
00666          newconv = maxval(abs(scalefac2-scalefac1)/scalefac1)
00667          if (newconv<0.0001d0 .or. abs(newconv-oldconv)<0.0001d0) then
00668             cont = .false.
00669          endif
00670          oldconv = newconv
00671       end do
00672       ! Ensure full energy conservation by scaling now according to full scalefac, not just the
00673       ! half used in the iteration loop
00674       do ip=1,nmodal
00675          scaledspec(ip)%S = multinomalspec(ip)%S*scalefac1(ip)
00676       enddo
00677       !
00678       ! Now check the total scaling that has taken place across the spectrum, also accounting
00679       ! for the fact that some parts of the spectra are set to zero. This differs from the
00680       ! scalefac1 and scalefac2 vectors in the loop that only adjust the part of the spectrum
00681       ! that is not zero.
00682       do ip=1,nmodal
00683          write(*,*)'Hm0m = ',4*sqrt(sum(scaledspec(ip)%S)*specin%dang*specin%df)
00684       enddo
00685       do ip=1,nmodal
00686          indvec = maxloc(scaledspec(ip)%S)
00687          scalefac1(ip) = scaledspec(ip)%S(indvec(1),indvec(2)) / &
00688          multinomalspec(ip)%S(indvec(1),indvec(2))-1.d0
00689       enddo
00690       !
00691       ! Warning and/or error criteria here if spectra overlap each other too much
00692       do ip=1,nmodal
00693          if(scalefac1(ip)>0.5d0) then
00694             if (forcepartition==1) then
00695                call writelog('lsw','(a,f0.0,a,i0,a,a,a)', &
00696                'Warning: ',scalefac1(ip)*100,'% of energy in spectrum partition ''',ip, &
00697                ''' in  ', trim(readfile),' is overlapped by other partitions')
00698                call writelog('lsw','',' Check spectral partitioning in ',trim(readfile))
00699             else
00700                call writelog('lswe','(a,f0.0,a,i0,a,a,a)', &
00701                'Error: ',scalefac1(ip)*100,'% of energy in spectrum partition ''',ip, &
00702                ''' in  ', trim(readfile),' is overlapped by other partitions')
00703                call writelog('lswe','','This spectrum overlaps too much with another spectrum partition.', &
00704                ' Check spectral partitioning in ',trim(readfile))
00705                call writelog('lswe','','If the partitioning should be carried out regardles of energy loss, ', &
00706                'set ''forcepartition = 1'' in ',trim(readfile))
00707                call halt_program
00708             endif
00709          elseif (scalefac1(ip)>0.2d0 .and. scalefac1(ip)<=0.5d0) then
00710             call writelog('lsw','(a,f0.0,a,i0,a,a,a)', &
00711             'Warning: ',scalefac1(ip)*100,'% of energy in spectrum partition ''',ip, &
00712             ''' in  ', trim(readfile),' is overlapped by other partitions')
00713             call writelog('lsw','',' Check spectral partitioning in ',trim(readfile))
00714          elseif (scalefac1(ip)<0.d0) then
00715             call writelog('lsw','(a,i0,a,a,a)','Warning: spectrum partition ''',ip,''' in  ',trim(readfile), &
00716             ' has been removed')
00717             call writelog('lsw','','This spectrum is entirely overlapped by another spectrum partition.',&
00718             ' Check spectral partitioning in ',trim(readfile))
00719          endif
00720       enddo
00721       !
00722       ! Now set total spectrum
00723       allocate(specin%S(specin%nf,specin%nang))
00724       specin%S = 0.d0
00725       do ip=1,nmodal
00726          specin%S = specin%S+scaledspec(ip)%S
00727       enddo
00728 
00729       deallocate(scaledspec)
00730       deallocate(tempmax)
00731       deallocate(scalefac1,scalefac2)
00732       deallocate(newvariance,oldvariance)
00733    endif
00734 
00735    ! We need frequency spectrum to ensure Sf remains correct between interpoloation
00736    ! routines
00737    allocate(specin%Sf(specin%nf))
00738    specin%Sf=0.d0
00739    do i=1,specin%nf
00740       do ii=1,specin%nang
00741          if (ii==1) then
00742             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(2)-specin%ang(1))
00743          elseif (ii==specin%nang) then
00744             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(ii)-specin%ang(ii-1))
00745          else
00746             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(ii+1)-specin%ang(ii-1))/2
00747          endif
00748       enddo
00749    enddo
00750 
00751    deallocate (Dd)
00752    deallocate(Hm0,fp,gam,mainang,scoeff)
00753    deallocate (x,y)
00754    deallocate(tempdir)
00755    ! TODO dereference pointers first....
00756    do ip=1,nmodal
00757       deallocate(multinomalspec(ip)%S)
00758    end do
00759    deallocate(multinomalspec)
00760 
00761 
00762 end subroutine read_jonswap_file
00763 
00764 
00765 
00766 ! -----------------------------------------------------------
00767 ! --------- JONSWAP  unscaled JONSWAP spectrum --------------
00768 ! -------------(used by read_jonswap_files)------------------
00769 subroutine jonswapgk(x,gam,y)
00770 
00771    IMPLICIT NONE
00772    ! Required input: - x           : nondimensional frequency, divided by the peak frequency
00773    !                 - gam         : peak enhancement factor, optional parameter (DEFAULT 3.3)
00774    !                 - y is output : nondimensional relative spectral density, equal to one at the peak
00775 
00776    real*8, INTENT(IN)                  :: gam
00777    real*8,dimension(:), INTENT(IN)     :: x
00778    real*8,dimension(:), INTENT(INOUT)  :: y
00779 
00780    ! Internal variables
00781    real*8,dimension(size(x))           :: xa, sigma, fac1, fac2, fac3, temp
00782 
00783    xa=abs(x)
00784 
00785    where (xa==0)
00786       xa=1e-20
00787    end where
00788 
00789    sigma=xa
00790 
00791    where (sigma<1.)
00792       sigma=0.07
00793    end where
00794 
00795    where (sigma>=1.)
00796       sigma=0.09
00797    end where
00798 
00799    temp=0*xa+1
00800 
00801    fac1=xa**(-5)
00802    fac2=exp(-1.25*(xa**(-4)))
00803    fac3=(gam*temp)**(exp(-((xa-1)**2)/(2*(sigma**2))))
00804 
00805    y=fac1*fac2*fac3
00806    y=y/maxval(y)
00807 
00808    return
00809 
00810 end subroutine jonswapgk
00811 
00812 
00813 ! --------------------------------------------------------------
00814 ! ----------------------Read SWAN files ------------------------
00815 ! --------------------------------------------------------------
00816 subroutine read_swan_file(par,readfile,specin)
00817 
00818    use params
00819    use logging_module
00820    use filefunctions
00821    use xmpi_module, only: Halt_Program
00822    use math_tools, only: flipv,flipa
00823 
00824    IMPLICIT NONE
00825 
00826    ! Input / output variables
00827    type(parameters), INTENT(IN)            :: par
00828    character(len=*), intent(IN)            :: readfile
00829    type(spectrum),intent(inout)            :: specin
00830 
00831    ! Internal variables
00832    character(6)                            :: rtext
00833    real*8                                  :: factor,exc
00834    integer                                 :: fid,switch
00835    integer                                 :: i,ii,ier,ier2,ier3
00836    logical                                 :: flipped
00837    integer                                 :: nt,Ashift
00838    real*8, dimension(:),allocatable        :: temp
00839    real*8, dimension(:,:),allocatable      :: tempA
00840 
00841    flipped =.false.
00842    switch  = 0
00843 
00844    call writelog('sl','','Reading from SWAN file ',trim(readfile),' ...')
00845    fid = create_new_fid()
00846    open(fid,file=readfile,form='formatted',status='old')
00847 
00848    ! Read file until RFREQ or AFREQ is found
00849    do while (switch==0)
00850       read(fid,'(a)',iostat=ier)rtext
00851       if (ier .ne. 0) then
00852          call report_file_read_error(readfile)
00853       endif
00854       if (rtext == 'RFREQ ') then
00855          switch = 1
00856       elseif (rtext == 'AFREQ ') then
00857          switch = 2
00858       end if
00859    end do
00860 
00861    ! Read nfreq and f
00862    ! Note f is not monotonically increasing in most simulations
00863    read(fid,*,iostat=ier)specin%nf
00864    if (ier .ne. 0) then
00865       call report_file_read_error(readfile)
00866    endif
00867    allocate(specin%f(specin%nf))
00868    do i=1,specin%nf
00869       read(fid,*,iostat=ier)specin%f(i)
00870       if (ier .ne. 0) then
00871          call report_file_read_error(readfile)
00872       endif
00873    end do
00874 
00875    ! Convert to absolute frequencies:
00876    ! STILL TO BE DONE
00877    if (switch == 1) then
00878       specin%f = specin%f
00879    else
00880       specin%f = specin%f
00881    end if
00882 
00883    ! Read CDIR or NDIR
00884    read(fid,'(a)',iostat=ier)rtext
00885    if (ier .ne. 0) then
00886       call report_file_read_error(readfile)
00887    endif
00888    if (rtext == 'NDIR  ') then
00889       switch = 1
00890    elseif (rtext == 'CDIR  ') then
00891       switch = 2
00892    else
00893       call writelog('ewls','', 'SWAN directional bins keyword not found')
00894       call halt_program
00895    endif
00896 
00897    ! Read ndir, theta
00898    read(fid,*,iostat=ier)specin%nang
00899    if (ier .ne. 0) then
00900       call report_file_read_error(readfile)
00901    endif
00902    allocate(specin%ang(specin%nang))
00903    do i=1,specin%nang
00904       read(fid,*,iostat=ier)specin%ang(i)
00905       if (ier .ne. 0) then
00906          call report_file_read_error(readfile)
00907       endif
00908    end do
00909 
00910    ! Convert angles to cartesian degrees relative to East
00911    if (switch == 1) then
00912       ! nautical to cartesian East
00913       specin%ang = 270.d0-specin%ang
00914    else
00915       ! cartesian to cartesian East
00916       specin%ang = specin%ang-par%dthetaS_XB
00917       ! dthetaS_XB is the (counter-clockwise) angle in the degrees to rotate from the x-axis in SWAN to the
00918       ! x-axis pointing East
00919    end if
00920 
00921    ! Ensure angles are increasing instead of decreasing
00922    if (specin%ang(2)<specin%ang(1)) then
00923       call flipv(specin%ang,size(specin%ang))
00924       flipped=.true.
00925    end if
00926 
00927    nt = 0
00928    Ashift = 0
00929    ! Make sure that all angles are in range of 0 to 360 degrees
00930    if(minval(specin%ang)<0.d0)then
00931       allocate (temp(specin%nang))
00932       Ashift=-1
00933       temp=0.d0
00934       do i=1,specin%nang
00935          if (specin%ang(i)<0.d0) then
00936             specin%ang(i)=specin%ang(i)+360.0d0
00937             nt = nt+1
00938          endif
00939       enddo
00940       temp(1:specin%nang-nt)=specin%ang(nt+1:specin%nang)
00941       temp(specin%nang-nt+1:specin%nang)=specin%ang(1:nt)
00942       specin%ang=temp
00943       deallocate(temp)
00944    elseif(maxval(specin%ang)>360.0d0)then
00945       allocate (temp(specin%nang))
00946       Ashift=1
00947       temp=0.d0
00948       do i=1,specin%nang
00949          if (specin%ang(i)>360.d0) then
00950             specin%ang(i)=specin%ang(i)-360.0d0
00951             nt = nt+1
00952          endif
00953       enddo
00954       temp(nt+1:specin%nang)=specin%ang(1:specin%nang-nt)
00955       temp(1:nt)=specin%ang(specin%nang-nt+1:specin%nang)
00956       specin%ang=temp
00957       deallocate(temp)
00958    endif
00959 
00960    ! convert to radians
00961    specin%ang=specin%ang*par_pi/180
00962    specin%dang=specin%ang(2)-specin%ang(1)
00963 
00964    ! Skip Quant, next line, read VaDens or EnDens
00965    read(fid,'(a)',iostat=ier)rtext
00966    read(fid,'(a)',iostat=ier2)rtext
00967    read(fid,'(a)',iostat=ier3)rtext
00968    if (ier+ier2+ier3 .ne. 0) then
00969       call report_file_read_error(readfile)
00970    endif
00971    if (rtext == 'VaDens') then
00972       switch = 1
00973    elseif (rtext == 'EnDens') then
00974       switch = 2
00975    else
00976       call writelog('slwe','', 'SWAN VaDens/EnDens keyword not found')
00977       call halt_program
00978    end if
00979    read(fid,'(a)',iostat=ier)rtext
00980    read(fid,*,iostat=ier2)exc
00981    if (ier+ier2 .ne. 0) then
00982       call report_file_read_error(readfile)
00983    endif
00984 
00985    i=0
00986    ! Find FACTOR keyword
00987    do while (i==0)
00988       read(fid,'(a)',iostat=ier)rtext
00989       if (ier .ne. 0) then
00990          call report_file_read_error(readfile)
00991       endif
00992       if (rtext == 'FACTOR') then
00993          i=1
00994       elseif (rtext == 'ZERO  ') then
00995          call writelog('lswe','','Zero energy density input for this point')
00996          call halt_program
00997       elseif (rtext == 'NODATA') then
00998          call writelog('lwse','','SWAN file has no data for this point')
00999          call halt_program
01000       end if
01001    end do
01002    read(fid,*,iostat=ier)factor
01003    if (ier .ne. 0) then
01004       call report_file_read_error(readfile)
01005    endif
01006 
01007    ! Read 2D S array
01008    allocate(specin%S(specin%nf,specin%nang))
01009    do i=1,specin%nf
01010       read(fid,*,iostat=ier)(specin%S(i,ii),ii=1,specin%nang)
01011       if (ier .ne. 0) then
01012          call report_file_read_error(readfile)
01013       endif
01014    end do
01015 
01016    ! Finished reading file
01017    close(fid)
01018 
01019    ! Replace exception value
01020    where (specin%S == exc)
01021       specin%S = 0.d0
01022    endwhere
01023 
01024    ! If angles were decreasing, flip S_array as also dir is flipped
01025    if (flipped) then
01026       call flipa(specin%S,specin%nf,specin%nang,2)
01027    end if
01028 
01029    ! If the order of the angles in specin%ang was reordered, so the same in
01030    ! specin%S array
01031    if(Ashift==-1)then
01032       allocate(tempA(specin%nf,specin%nang))
01033       tempA=0
01034       tempA(:,1:specin%nang-nt)=specin%S(:,nt+1:specin%nang)
01035       tempA(:,specin%nang-nt+1:specin%nang)=specin%S(:,1:nt)
01036       specin%S=tempA
01037       deallocate(tempA)
01038    elseif (Ashift==1) then
01039       allocate(tempA(specin%nf,specin%nang))
01040       tempA=0
01041       tempA(:,nt+1:specin%nang)=specin%S(:,1:specin%nang-nt)
01042       tempA(:,1:nt)=specin%S(:,specin%nang-nt+1:specin%nang)
01043       specin%S=tempA
01044       deallocate(tempA)
01045    endif
01046 
01047    ! multiply by SWAN output factor
01048    specin%S=specin%S*factor
01049 
01050    ! Convert from energy density to variance density
01051    if (switch == 2) then
01052       specin%S=specin%S/(waveBoundaryParameters%rho*par_g)
01053    end if
01054 
01055    ! Convert to m2/Hz/rad
01056    specin%S=specin%S*180/par_pi
01057 
01058    ! We need a value for spreading. The assumption is that it is less than 1000
01059    ! This way, wp%fgen will not be set to just one angle.
01060    specin%scoeff = -1.d0
01061    ! We need to know if hm0 was set explicitly, not the case for Swan files
01062    specin%hm0 = -1.d0
01063 
01064    ! We need frequency spectrum to ensure Sf remains correct between interpoloation
01065    ! routines
01066    allocate(specin%Sf(specin%nf))
01067    specin%Sf=0.d0
01068    do i=1,specin%nf
01069       do ii=1,specin%nang
01070          if (ii==1) then
01071             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(2)-specin%ang(1))
01072          elseif (ii==specin%nang) then
01073             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(ii)-specin%ang(ii-1))
01074          else
01075             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(ii+1)-specin%ang(ii-1))/2
01076          endif
01077       enddo
01078    enddo
01079 
01080 end subroutine read_swan_file
01081 
01082 
01083 ! --------------------------------------------------------------
01084 ! -----------------Read variance density files -----------------
01085 ! --------------------------------------------------------------
01086 subroutine read_vardens_file(par,readfile,specin)
01087 
01088    use params
01089    use logging_module
01090    use filefunctions
01091    use xmpi_module, only: Halt_Program
01092    use math_tools, only: flipv,flipa
01093 
01094    IMPLICIT NONE
01095 
01096    ! Input / output variables
01097    type(parameters), INTENT(IN)            :: par
01098    character(len=*), intent(IN)            :: readfile
01099    type(spectrum),intent(inout)            :: specin
01100 
01101    ! Internal variables
01102    integer                                 :: fid,i,ii,nnz,ier,nt,Ashift
01103    real*8,dimension(:),allocatable         :: Sd,temp
01104    real*8, dimension(:,:),allocatable      :: tempA
01105 
01106    ! Open file to start read
01107    call writelog('sl','','Reading from vardens file ',trim(readfile),' ...')
01108    fid = create_new_fid()
01109    open(fid,file=readfile,form='formatted',status='old')
01110 
01111    ! Read number of frequencies and frequency vector
01112    read(fid,*,iostat=ier)specin%nf
01113    if (ier .ne. 0) then
01114       call report_file_read_error(readfile)
01115    endif
01116    allocate(specin%f(specin%nf))
01117    do i=1,specin%nf
01118       read(fid,*,iostat=ier)specin%f(i)
01119       if (ier .ne. 0) then
01120          call report_file_read_error(readfile)
01121       endif
01122    end do
01123 
01124    ! Read number of angles and angles vector
01125    read(fid,*,iostat=ier)specin%nang
01126    if (ier .ne. 0) then
01127       call report_file_read_error(readfile)
01128    endif
01129    allocate(specin%ang(specin%nang))
01130    do i=1,specin%nang
01131       read(fid,*,iostat=ier)specin%ang(i)
01132       if (ier .ne. 0) then
01133          call report_file_read_error(readfile)
01134       endif
01135    end do
01136    ! Directions should span 0-360 degrees, not negative
01137    nt = 0
01138    Ashift = 0
01139    ! Make sure that all angles are in range of 0 to 360 degrees
01140    if(minval(specin%ang)<0.d0)then
01141       allocate (temp(specin%nang))
01142       Ashift=-1
01143       temp=0.d0
01144       do i=1,specin%nang
01145          if (specin%ang(i)<0.d0) then
01146             specin%ang(i)=specin%ang(i)+360.0d0
01147             nt = nt+1
01148          endif
01149       enddo
01150       temp(1:specin%nang-nt)=specin%ang(nt+1:specin%nang)
01151       temp(specin%nang-nt+1:specin%nang)=specin%ang(1:nt)
01152       specin%ang=temp
01153       deallocate(temp)
01154    elseif(maxval(specin%ang)>360.0d0)then
01155       allocate (temp(specin%nang))
01156       Ashift=1
01157       temp=0.d0
01158       do i=1,specin%nang
01159          if (specin%ang(i)>360.d0) then
01160             specin%ang(i)=specin%ang(i)-360.0d0
01161             nt = nt+1
01162          endif
01163       enddo
01164       temp(nt+1:specin%nang)=specin%ang(1:specin%nang-nt)
01165       temp(1:nt)=specin%ang(specin%nang-nt+1:specin%nang)
01166       specin%ang=temp
01167       deallocate(temp)
01168    endif
01169 
01170    ! Convert from degrees to rad
01171    specin%ang=specin%ang*par_pi/180
01172    specin%dang=specin%ang(2)-specin%ang(1)
01173 
01174    ! Read 2D S array
01175    allocate(specin%S(specin%nf,specin%nang))
01176    do i=1,specin%nf
01177       read(fid,*,iostat=ier)(specin%S(i,ii),ii=1,specin%nang)
01178       if (ier .ne. 0) then
01179          call report_file_read_error(readfile)
01180       endif
01181    end do
01182 
01183    ! If the order of the angles in specin%ang was reordered, so the same in
01184    ! specin%S array
01185    if(Ashift==-1)then
01186       allocate(tempA(specin%nf,specin%nang))
01187       tempA=0
01188       tempA(:,1:specin%nang-nt)=specin%S(:,nt+1:specin%nang)
01189       tempA(:,specin%nang-nt+1:specin%nang)=specin%S(:,1:nt)
01190       specin%S=tempA
01191       deallocate(tempA)
01192    elseif (Ashift==1) then
01193       allocate(tempA(specin%nf,specin%nang))
01194       tempA=0
01195       tempA(:,nt+1:specin%nang)=specin%S(:,1:specin%nang-nt)
01196       tempA(:,1:nt)=specin%S(:,specin%nang-nt+1:specin%nang)
01197       specin%S=tempA
01198       deallocate(tempA)
01199    endif
01200 
01201    ! Finished reading file
01202    close(fid)
01203 
01204    ! Convert to m2/Hz/rad
01205    specin%S=specin%S*180/par_pi
01206 
01207    ! We need a value for spreading. The assumption is that it is less than 1000
01208    ! if more than one direction column has variance. If only one column has variance
01209    ! we assume the model requires long crested waves, and wp%thetagen should be exactly
01210    ! equal to the input direction. We then also need to find the dominant angle.
01211    ! First flatten spectrum to direction only, then determine if all but one are zero,
01212    ! use the direction of the non-zero as the main wave direction, set spreading to
01213    ! a high value (greater than 1000). Else set spreading to a negative value.
01214    allocate(Sd(specin%nang))
01215    Sd = sum(specin%S,DIM = 1)
01216    nnz = count(Sd>0.d0)
01217    if (nnz == 1) then
01218       specin%scoeff = 1024.d0
01219       specin%dir0 = specin%ang(minval(maxloc(Sd)))
01220    else
01221       specin%scoeff = -1.d0
01222    endif
01223 
01224    ! We need frequency spectrum to ensure Sf remains correct between interpoloation
01225    ! routines
01226    allocate(specin%Sf(specin%nf))
01227    specin%Sf=0.d0
01228    do i=1,specin%nf
01229       do ii=1,specin%nang
01230          if (ii==1) then
01231             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(2)-specin%ang(1))
01232          elseif (ii==specin%nang) then
01233             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(ii)-specin%ang(ii-1))
01234          else
01235             specin%Sf(i) = specin%Sf(i)+specin%S(i,ii)*abs(specin%ang(ii+1)-specin%ang(ii-1))/2
01236          endif
01237       enddo
01238    enddo
01239 
01240 
01241    ! We need to know if hm0 was set explicitly, not the case for vardens files
01242    specin%hm0 = -1.d0
01243 
01244    ! Free memory
01245    deallocate(Sd)
01246 end subroutine read_vardens_file
01247 
01248 
01249 ! --------------------------------------------------------------
01250 ! ------------- Interpolate to standard spectrum ---------------
01251 ! --------------------------------------------------------------
01252 subroutine interpolate_spectrum(specin,specinterp,par,fmax)
01253 
01254    use interp
01255    use params
01256 
01257    IMPLICIT NONE
01258 
01259    ! input/output
01260    type(spectrum),intent(in)            :: specin
01261    type(spectrum),intent(inout)         :: specinterp
01262    type(parameters),intent(in)          :: par
01263    real*8, intent(in)                   :: fmax
01264    ! internal
01265    integer                              :: i,j,dummy
01266    real*8                               :: m0,df,dang
01267    real*8,dimension(naint)              :: Sd
01268    real*8                               :: hm0pre,hm0post,Sfnow,factor,tempt0
01269 
01270    ! allocate size of f,ang,Sf and S arrays in specinterp
01271    allocate(specinterp%f(nfint))
01272    allocate(specinterp%ang(naint))
01273    allocate(specinterp%Sf(nfint))
01274    allocate(specinterp%S(nfint,naint))
01275 
01276    ! fill f and ang arrays
01277    specinterp%nf = nfint
01278    specinterp%df = fmax/(nfint-1)     ! this usually gives a range of 0-1Hz,
01279    ! with 1/800Hz resolution
01280    do i=1,nfint
01281       specinterp%f(i)=(i-1)*specinterp%df
01282    enddo
01283    specinterp%nang = naint
01284    specinterp%dang = 2*par_pi/(naint-1) ! this is exactly the same as in the JONSWAP construction
01285    do i=1,specinterp%nang
01286       specinterp%ang(i)=(i-1)*specinterp%dang
01287    enddo
01288 
01289    ! If hm0 was set explicitly, then use that, else calculate hm0
01290    if (specin%hm0>0.d0) then
01291       hm0pre = specin%hm0
01292    else
01293       ! pre-interpolation hm0 value (can be on a non-monotonic f,ang grid)
01294       m0 = 0
01295       do j=1,specin%nang
01296          do i=1,specin%nf
01297             df = specin%f(max(2,i))-specin%f(max(1,i-1))
01298             dang = specin%ang(max(2,j))-specin%ang(max(1,j-1))
01299             m0 = m0 + specin%S(i,j)*df*dang
01300          enddo
01301       enddo
01302       hm0pre = 4*sqrt(m0)
01303    endif
01304 
01305    ! interpolation (no extrapolation) of input 2D spectrum to standard 2D spectrum
01306    do j=1,naint
01307       do i=1,nfint
01308          call linear_interp_2d(specin%f,specin%nf,specin%ang,specin%nang,specin%S, &
01309          specinterp%f(i),specinterp%ang(j),specinterp%S(i,j),'interp',0.d0)
01310       enddo
01311    enddo
01312    ! hm0 post (is always on a monotonic f,ang grid
01313    m0 = sum(specinterp%S)*specinterp%df*specinterp%dang
01314    hm0post = 4*sqrt(m0)
01315 
01316    ! correct the wave energy to ensure hm0post == hm0pre
01317    ! specinterp%S = (hm0pre/hm0post)**2*specinterp%S
01318    ! This is done later using Sf
01319 
01320    ! calculate 1D spectrum, summed over directions
01321    specinterp%Sf = sum(specinterp%S, DIM = 2)*specinterp%dang
01322 
01323    ! correct the wave energy by setting Sfpost == Sfpre
01324    do i=1,nfint
01325       if (specinterp%f(i)>=minval(specin%f) .and. specinterp%f(i)<=maxval(specin%f)) then
01326          call LINEAR_INTERP(specin%f,specin%Sf,specin%nf,specinterp%f(i),Sfnow,dummy)
01327          if (specinterp%Sf(i)>0.d0 .and. Sfnow>0.d0) then
01328             factor = Sfnow/specinterp%Sf(i)
01329             specinterp%Sf(i)  = specinterp%Sf(i)*factor
01330             specinterp%S(i,:) = specinterp%S(i,:)*factor
01331          elseif (Sfnow==0.d0) then
01332             specinterp%Sf(i)  = 0.d0
01333             specinterp%S(i,:) = 0.d0
01334          else
01335             specinterp%Sf(i)  = Sfnow
01336             dummy = maxval(maxloc(specin%S(i,:)))
01337             tempt0 = specin%ang(dummy)
01338             dummy = maxval(minloc(abs(specinterp%ang-tempt0)))
01339             specinterp%S(i,dummy) = Sfnow/specinterp%dang
01340          endif
01341       endif
01342    enddo
01343 
01344    ! calculate other wave statistics from interpolated spectrum
01345    m0 = sum(specinterp%Sf)*specinterp%df
01346    specinterp%hm0 = 4*sqrt(m0)
01347    Sd = sum(specinterp%S, DIM = 1)*specinterp%df
01348    i  = maxval(maxloc(Sd))
01349    specinterp%dir0 = 270.d0 - specinterp%ang(i)*180/par_pi  ! converted back into nautical degrees
01350    i  = maxval(maxloc(specinterp%Sf))
01351    specinterp%fp = specinterp%f(i)
01352    call tpDcalc(specinterp%Sf,specinterp%f,specinterp%trep,par%trepfac,par%Tm01switch)
01353    specinterp%dirm = 270.d0-180.d0/par_pi*atan2( sum(sin(specinterp%ang)*Sd)/sum(Sd),&
01354    sum(cos(specinterp%ang)*Sd)/sum(Sd) )
01355 
01356 end subroutine interpolate_spectrum
01357 
01358 ! --------------------------------------------------------------
01359 ! ----------- Small subroutine to determine if the  ------------
01360 ! ---------- global repeatwbc should be true or false ----------
01361 subroutine set_repeatwbc
01362 
01363    implicit none
01364    ! internal
01365    integer                                           :: i
01366 
01367    ! set default to repeat all boundary conditions
01368    waveSpectrumAdministration%repeatwbc = .true.
01369    ! find any spectrum that cannot be repeated, then change global
01370    ! repeatwbc to false
01371    do i=1,nspectra
01372       if (.not. bcfiles(i)%repeat) then
01373          waveSpectrumAdministration%repeatwbc = .false.
01374       endif
01375    enddo
01376 
01377 end subroutine set_repeatwbc
01378 
01379 ! --------------------------------------------------------------
01380 ! ----------- Small subroutine to set the filenames ------------
01381 ! ----------- of the boundary condition output files -----------
01382 subroutine set_bcfilenames(wp)
01383 
01384    implicit none
01385    ! input/output
01386    type(waveparamsnew),intent(inout)            :: wp
01387    ! internal
01388    integer                                      :: i1,i2,i3,i4,i5
01389 
01390    if (waveSpectrumAdministration%repeatwbc) then
01391       wp%Efilename = 'E_reuse.bcf'
01392       wp%qfilename = 'q_reuse.bcf'
01393       wp%nhfilename = 'nh_reuse.bcf'
01394    else
01395       i1=floor(real(bccount)/10000)
01396       i2=floor(real(bccount-i1*10000)/1000)
01397       i3=floor(real(bccount-i1*10000-i2*1000)/100)
01398       i4=floor(real(bccount-i1*10000-i2*1000-i3*100)/10)
01399       i5=bccount-i1*10000-i2*1000-i3*100-i4*10
01400       wp%Efilename='E_series'//char(48+i1)//char(48+i2)//char(48+i3)//char(48+i4)//char(48+i5)//'.bcf'
01401       wp%qfilename='q_series'//char(48+i1)//char(48+i2)//char(48+i3)//char(48+i4)//char(48+i5)//'.bcf'
01402       wp%nhfilename='nh_series'//char(48+i1)//char(48+i2)//char(48+i3)//char(48+i4)//char(48+i5)//'.bcf'
01403    endif
01404 
01405 end subroutine set_bcfilenames
01406 
01407 ! --------------------------------------------------------------
01408 ! ----------- Merge all separate spectra into one --------------
01409 ! -------------- average spectrum for other use ----------------
01410 subroutine generate_combined_spectrum(specinterp,combspec)
01411 
01412    implicit none
01413    type(spectrum),dimension(nspectra),intent(in)   :: specinterp
01414    type(spectrum),intent(inout)                    :: combspec
01415    integer                                         :: iloc
01416    real*8,dimension(naint)                         :: Sd
01417    real*8,dimension(3)                             :: peakSd,peakang
01418    real*8,dimension(:),allocatable                 :: tempSf
01419 
01420    allocate(combspec%f(nfint))
01421    allocate(combspec%Sf(nfint))
01422    allocate(combspec%ang(naint))
01423    allocate(combspec%S(nfint,naint))
01424    combspec%f=specinterp(1)%f
01425    combspec%nf=nfint
01426    combspec%df=specinterp(1)%df
01427    combspec%ang=specinterp(1)%ang
01428    combspec%nang=naint
01429    combspec%dang=specinterp(1)%dang
01430    combspec%trep = 0.d0
01431    combspec%S=0.d0
01432    combspec%Sf=0.d0
01433    combspec%hm0=0.d0
01434 
01435    do iloc = 1,nspectra
01436       combspec%S    = combspec%S   +specinterp(iloc)%S   /nspectra
01437       combspec%Sf   = combspec%Sf  +specinterp(iloc)%Sf  /nspectra
01438    enddo
01439    !
01440    ! Calculate peak wave angle
01441    !
01442    ! frequency integrated variance array
01443    Sd = sum(combspec%S,DIM=1)
01444    ! peak location of f-int array
01445    iloc = maxval(maxloc(Sd))
01446    ! pick two neighbouring directional bins, including effect of closing circle at
01447    ! 0 and 2pi rad
01448    if (iloc>1 .and. iloc<naint) then
01449       peakSd = (/Sd(iloc-1),Sd(iloc),Sd(iloc+1)/)
01450       peakang = (/combspec%ang(iloc-1),combspec%ang(iloc),combspec%ang(iloc+1)/)
01451    elseif (iloc==1) then
01452       peakSd = (/Sd(naint),Sd(1),Sd(2)/)
01453       peakang = (/combspec%ang(naint)-2*par_pi,combspec%ang(1),combspec%ang(2)/)
01454    elseif (iloc==naint) then
01455       peakSd = (/Sd(naint-1),Sd(naint),Sd(1)/)
01456       peakang = (/combspec%ang(naint-1),combspec%ang(naint),combspec%ang(1)+2*par_pi/)
01457    endif
01458    ! dir0 calculated as mean over peak and two neighbouring cells
01459    combspec%dir0 = sum(peakSd*peakang)/sum(peakSd)
01460    ! return to 0<=dir0<=2*par_pi
01461    if (combspec%dir0>2*par_pi) then
01462       combspec%dir0 = combspec%dir0-2*par_pi
01463    elseif (combspec%dir0<0) then
01464       combspec%dir0 = combspec%dir0+2*par_pi
01465    endif
01466    !
01467    ! Compute peak wave frequency
01468    !
01469    allocate(tempSf(size(combspec%Sf)))
01470    tempSf=0*combspec%Sf
01471    ! find frequency range of 95% wave energy around peak
01472    where (combspec%Sf>0.95d0*maxval(combspec%Sf))
01473       tempSf=combspec%Sf
01474    end where
01475    ! smoothed peak is weighted mean frequency of 95% range
01476    combspec%fp = sum(tempSf*combspec%f)/sum(tempSf)
01477    !
01478    ! Compute representative wave period
01479    !
01480    call tpDcalc(combspec%Sf,combspec%f,combspec%trep,par%trepfac,par%Tm01switch)
01481    !
01482    ! Compute combined wave height
01483    do iloc = 1,nspectra
01484       combspec%hm0 = combspec%hm0+specinterp(iloc)%hm0**2/nspectra
01485    enddo
01486    combspec%hm0 = sqrt(combspec%hm0)
01487 
01488 end subroutine generate_combined_spectrum
01489 
01490 
01491 ! --------------------------------------------------------------
01492 ! ----------- Choose wave train components based on ------------
01493 ! --------------------- combined spectrum ----------------------
01494 subroutine generate_wavetrain_components(combspec,wp)
01495 
01496 #ifdef BUILDXBEACH
01497    use logging_module
01498    use interp
01499    use wave_functions_module, only: iteratedispersion
01500 #endif
01501    use wave_boundary_datastore
01502    use math_tools
01503 
01504    implicit none
01505    ! input/output
01506    type(spectrum),intent(in)                    :: combspec
01507    type(waveparamsnew),intent(inout)            :: wp
01508    ! internal
01509    integer                                      :: i,ii
01510    integer                                      :: ind1,ind2,dummy
01511    real*8,dimension(:),allocatable              :: randnums,pdflocal,cdflocal
01512    real*8                                       :: L0,L,kmax,fmax,dummy_real
01513 
01514 
01515    ! If we are running non-hydrostatic boundary conditions, we want to remove
01516    ! very high frequency components, as these will not be computed well anyway
01517    if (waveBoundaryParameters%nonhspectrum) then
01518       kmax = wdmax/hb0
01519       fmax = par_g*kmax*tanh(kmax*hb0)/2/par_pi
01520    else
01521       ! this is really already taken into account
01522       ! by specifying waveBoundaryParameters%sprdthr
01523       fmax = 2*maxval(combspec%f)
01524    endif
01525 
01526    ! Determine frequencies around peak frequency of one-dimensional
01527    ! non-directional variance density spectrum, based on factor sprdthr, which
01528    ! should be included in the determination of the wave boundary conditions
01529    call frange(combspec%f,combspec%Sf,fmax,ind1,ind2)
01530 
01531    ! Calculate number of wave components to be included in determination of the
01532    ! wave boundary conditions based on the wave record length and width of the
01533    ! wave frequency range
01534    wp%K = ceiling(wp%rtbc*(combspec%f(ind2)-combspec%f(ind1))+1)
01535    ! also include minimum number of components
01536    wp%K = max(wp%K,Kmin)
01537 
01538    ! Allocate space in waveparams for all wave train components
01539    allocate(wp%fgen(wp%K))
01540    allocate(wp%thetagen(wp%K))
01541    allocate(wp%phigen(wp%K))
01542    allocate(wp%kgen(wp%K))
01543    allocate(wp%wgen(wp%K))
01544 
01545    ! Select equidistant wave components between the earlier selected range of
01546    ! frequencies around the peak frequency in the frange subfunction
01547    wp%dfgen = (combspec%f(ind2)-combspec%f(ind1))/(wp%K-1)
01548    do i=1,wp%K
01549       wp%fgen(i)=combspec%f(ind1)+(i-1)*wp%dfgen
01550    enddo
01551 
01552    ! This subroutine needs to generate random phase / directions for the individual
01553    ! wave trains. Due to some strange Fortran properties, it is better to select
01554    ! one long vector with random numbers for both the phase and the direction, than
01555    ! one vector for each.
01556    ! Update random seed, if requested
01557    allocate(randnums(2*wp%K))
01558    ! Spin up random number generator, else all low seed numbers mean random sequence
01559    ! start at ~0. Don't know how much spin up is required (strictly no spin-up needed
01560    ! if random integer given as seed)
01561    dummy_real = random(waveBoundaryParameters%randomseed)
01562    do i=1,10
01563       dummy_real = random(0)
01564    enddo
01565    do i=1,2*wp%K
01566       randnums(i) = random(0)
01567    enddo
01568 
01569    ! Determine a random phase for each wave train component between 0 and 2pi
01570    wp%phigen=randnums(1:wp%K)*2*par_pi
01571 
01572    ! Determine random directions for each wave train component, based on the CDF of
01573    ! the directional spectrum. For each wave train we will interpolate the directional
01574    ! distribution at that frequency, generate a CDF, and then interpolate the wave
01575    ! train direction from a random number draw and the CDF.
01576    allocate(pdflocal(naint))
01577    allocate(cdflocal(naint))
01578    do i=1,wp%K
01579       ! interpolate spectrum at this frequency per angle in the spectrum
01580       do ii=1,naint
01581 #ifdef BUILDXBEACH
01582          call LINEAR_INTERP(combspec%f,combspec%S(:,ii),combspec%nf, wp%fgen(i),pdflocal(ii),dummy)
01583 #else
01584          ! interpolate in other systems
01585 #endif
01586       enddo
01587       ! convert to pdf by ensuring total integral == 1, assuming constant directional bin size
01588       pdflocal = pdflocal/sum(pdflocal)
01589       ! convert to cdf by trapezoidal integration, which is not biased for integration
01590       ! direction.
01591       ! Boundary condition, which may be nonzero:
01592       cdflocal(1) = pdflocal(1)
01593       do ii=2,naint
01594          cdflocal(ii) = cdflocal(ii-1) + (pdflocal(ii)+pdflocal(ii-1))/2
01595          ! Note: this only works if the directional
01596          ! bins are constant in size. Assumed multiplication
01597          ! by one.
01598       enddo
01599       ! interpolate random number draw across the cdf. Note that cdf(1) is not assumed to be zero and
01600       ! there is a posibility of drawing less than cdf(1). Therefore, if the random number is .lt. cdf(1),
01601       ! interpolation should take place across the back of the angle spectrum
01602       ! (i.e., from theta(end)-2pi : theta(1)).
01603       ! Note that we are using the second half of randnums now (K+1:end)
01604       if (randnums(wp%K+i)>=cdflocal(1)) then
01605 #ifdef BUILDXBEACH
01606          call LINEAR_INTERP(cdflocal,combspec%ang,naint,randnums(wp%K+i), wp%thetagen(i),dummy)
01607 #else
01608          ! interpolate in other systems
01609 #endif
01610       else
01611 #ifdef BUILDXBEACH
01612          call LINEAR_INTERP((/0.d0,cdflocal(1)/),(/combspec%ang(naint)-2*par_pi,combspec%ang(1)/), &
01613          2,randnums(wp%K+i),wp%thetagen(i),dummy)
01614 #else
01615          ! interpolate in other systems
01616 #endif
01617       endif
01618       ! ensure wave direction 0<=theta<2pi
01619       wp%thetagen(i) = mod(wp%thetagen(i),2*par_pi)
01620    enddo
01621 
01622    ! determine wave number for each wave train component, using standard dispersion relation
01623    ! solver from wave_functions module. This function returns a negative wave length if the
01624    ! solver did not converge.
01625 #ifdef BUILDXBEACH
01626    do i=1,wp%K
01627       L0 = par_g*(1/wp%fgen(i))**2/2/par_pi    ! deep water wave length
01628       L = iteratedispersion(L0,L0,par_pi,hb0)
01629       if (L<0.d0) then
01630          call writelog('lsw','','No dispersion convergence found for wave train ',i, &
01631          ' in boundary condition generation')
01632          L = -L
01633       endif
01634       wp%kgen(i) = 2*par_pi/L
01635    enddo
01636 #else
01637    ! do dispersion relation in other model
01638 #endif
01639 
01640    ! Angular frequency
01641    wp%wgen = 2*par_pi*wp%fgen
01642 
01643    ! Free memory
01644    deallocate(pdflocal,cdflocal,randnums)
01645 
01646 end subroutine generate_wavetrain_components
01647 
01648 ! -----------------------------------------------------------
01649 ! ----------- Small subroutine to determine -----------------
01650 ! ------------ representative wave period -------------------
01651 subroutine tpDcalc(Sf,f,Trep,trepfac,switch)
01652 
01653    implicit none
01654 
01655    real*8, dimension(:), intent(in)        :: Sf, f
01656    real*8, intent(out)                     :: Trep
01657    real*8, intent(in)                      :: trepfac
01658    integer, intent(in)                     :: switch
01659 
01660    real*8, dimension(:),allocatable        :: temp
01661 
01662    allocate(temp(size(Sf)))
01663    temp=0.d0
01664    where (Sf>=trepfac*maxval(Sf))
01665       temp=1.d0
01666    end where
01667 
01668    if (switch == 1) then
01669       Trep=sum(temp*Sf)/sum(temp*Sf*f)    ! Tm01
01670    else
01671       Trep = sum(temp*Sf/max(f,0.001d0))/sum(temp*Sf)    ! Tm-1,0
01672    endif
01673 
01674    deallocate(temp)
01675 
01676 end subroutine tpDcalc
01677 
01678 
01679 ! -----------------------------------------------------------
01680 ! ---- Small subroutine to determine f-range round peak -----
01681 ! -----------------------------------------------------------
01682 subroutine frange(f,Sf,fmax,firstp,lastp,findlineout)
01683 
01684    use wave_boundary_datastore
01685 
01686    implicit none
01687 
01688    real*8, dimension(:), intent(in)        :: f,Sf
01689    real*8,intent(in)                       :: fmax
01690 
01691    integer, intent(out)                    :: firstp, lastp
01692 
01693    real*8, dimension(:), intent(out),allocatable,optional  :: findlineout
01694    real*8, dimension(:),allocatable        :: temp, findline
01695    integer                                 :: i = 0
01696 
01697    ! find frequency range around peak
01698    allocate(findline(size(Sf)))
01699    findline=0*Sf
01700    where (Sf>waveBoundaryParameters%sprdthr*maxval(Sf))
01701       findline=1
01702    end where
01703 
01704    ! find frequency range below fmax
01705    where(f>fmax)
01706       findline = 0
01707    endwhere
01708 
01709    firstp=maxval(maxloc(findline))         ! Picks the first "1" in temp
01710 
01711    allocate (temp(size(findline)))
01712    temp=(/(i,i=1,size(findline))/)
01713    lastp=maxval(maxloc(temp*findline))     ! Picks the last "1" in temp
01714 
01715    if (present(findlineout)) then
01716       allocate(findlineout(size(Sf)))
01717       findlineout=findline
01718    endif
01719    deallocate(temp, findline)
01720 
01721 end subroutine frange
01722 
01723 
01724 ! --------------------------------------------------------------
01725 ! ---------------- Setup time axis for waves -------------------
01726 ! --------------------------------------------------------------
01727 subroutine generate_wave_time_axis(wp)
01728 
01729    use wave_boundary_datastore
01730 
01731    implicit none
01732    ! input/output
01733    type(waveparamsnew),intent(inout)            :: wp
01734    ! internal
01735    integer                                      :: ntaper, indend
01736    integer                                      :: i
01737 
01738 
01739 
01740    ! First assume that internal and bc-writing time step is the same
01741    wp%dtin = wp%dtbc
01742    wp%dtchanged = .false.
01743    wp%tslenbc = nint(wp%rtbc/wp%dtbc)+1
01744 
01745    ! Check whether the internal frequency is high enough to describe the highest frequency
01746    ! wave train returned from frange (which can be used in the boundary conditions)
01747    if (.not.waveBoundaryParameters%nonhspectrum) then
01748       if (wp%dtin>0.5d0/wp%fgen(wp%K)) then
01749          wp%dtin = 0.5d0/wp%fgen(wp%K)
01750          wp%dtchanged = .true.
01751       endif
01752    else
01753       if (wp%dtin>0.1d0/wp%fgen(wp%K)) then
01754          wp%dtin = 0.1d0/wp%fgen(wp%K)
01755          wp%dtchanged = .true.
01756       endif
01757    endif
01758 
01759    ! The length of the internal time axis should be even (for Fourier transform) and
01760    ! depends on the internal time step needed and the internal duration (~1/dfgen):
01761    wp%tslen = ceiling(1/wp%dfgen/wp%dtin)+1
01762    if (mod(wp%tslen,2)/=0) then
01763       wp%tslen = wp%tslen +1
01764    end if
01765 
01766    ! Now we can make the internal time axis
01767    wp%rtin = wp%tslen * wp%dtin
01768    allocate(wp%tin(wp%tslen))
01769    do i=1,wp%tslen
01770       wp%tin(i) = (i-1)*wp%dtin
01771    enddo
01772 
01773    ! Make a taper function to slowly increase and decrease the boundary condition forcing
01774    ! at the start and the end of the boundary condition file (including any time beyond
01775    ! the external rtbc
01776    allocate(wp%taperf(wp%tslen))
01777    allocate(wp%taperw(wp%tslen))
01778    ! fill majority with unity
01779    wp%taperf = 1.d0
01780    wp%taperw = 1.d0
01781    if (waveBoundaryParameters%nonhspectrum) then
01782       ! begin taper by building up the wave conditions over 2 wave periods
01783       ntaper = nint((2.0d0*waveSpectrumAdministration%Tbc)/wp%dtin)
01784    else
01785       ntaper = nint((5.d0*waveSpectrumAdministration%Tbc)/wp%dtin)
01786    endif
01787    do i=1,min(ntaper,size(wp%taperf))
01788       wp%taperf(i) = tanh(5.d0*i/ntaper)     ! multiplied by five because tanh(5)=~1
01789       wp%taperw(i) = tanh(5.d0*i/ntaper)
01790    enddo
01791    ! We do not want to taperw the end anymore. Instead we pass the wave height at the end of rtbc to
01792    ! the next wave generation iteration.
01793    ! end taper by finding where tin=rtbc, taper before that and set everything to zero after
01794    ! that.
01795    if (wp%tin(wp%tslen)>wp%rtbc) then
01796       indend = minval(minloc(wp%tin,MASK = wp%tin>=wp%rtbc))
01797    else
01798       indend = wp%tslen
01799    endif
01800    do i=1,min(ntaper,indend)
01801       wp%taperf(indend+1-i) = min(wp%taperf(indend+1-i),tanh(5.d0*i/ntaper))
01802    enddo
01803    wp%taperf(indend:wp%tslen) = 0.d0
01804    ind_end_taper = indend
01805 end subroutine generate_wave_time_axis
01806 
01807 
01808 ! --------------------------------------------------------------
01809 ! -------- Calculate variance at each spectrum location --------
01810 ! --------------------------------------------------------------
01811 subroutine generate_wave_train_variance(wp,specinterp)
01812 
01813 #ifdef BUILDXBEACH
01814    use interp
01815 #endif
01816 
01817    implicit none
01818    ! input/output
01819    type(waveparamsnew),intent(inout)            :: wp
01820    type(spectrum),dimension(nspectra),intent(in):: specinterp
01821    ! internal
01822    integer                                      :: i,ii, dummy
01823    real*8                                       :: hm0post
01824 
01825    ! allocate space for the variance arrays
01826    allocate(wp%vargen(nspectra))
01827    allocate(wp%vargenq(nspectra))
01828 
01829    ! Determine variance at each spectrum location
01830    do i=1,nspectra
01831       allocate(wp%vargen(i)%Sf(wp%K))
01832       allocate(wp%vargenq(i)%Sf(wp%K))
01833       do ii=1,wp%K
01834          ! In order to maintain energy density per frequency, an interpolation
01835          ! is carried out on the input directional variance density spectrum
01836          ! at the frequency and direction locations in fgen.
01837          call linear_interp(specinterp(i)%f, &
01838          specinterp(i)%Sf, &
01839          nfint, &
01840          wp%fgen(ii), &
01841          wp%vargen(i)%Sf(ii),dummy)
01842       enddo
01843       ! Correct variance to ensure the total variance remains the same as the total variance in the
01844       ! (interpolated) input spectrum
01845       hm0post = 4*sqrt(sum(wp%vargen(i)%Sf)*wp%dfgen)
01846       wp%vargen(i)%Sf   = (specinterp(i)%hm0/hm0post)**2*wp%vargen(i)%Sf
01847       ! For the generation of long waves we cannot use wp%vargen%Sf, because it contains an overestimation
01848       ! of energy in the peak frequencies. We can also not use the standard directionally-integrated spectrum
01849       ! because this stores all energy at fgen(K), where it is possible that for this current spectrum, there
01850       ! is no energy at S(f(K),theta(K0))
01851       ! The current solution is to take the minimum of both methods
01852       do ii=1,wp%K
01853          ! Map Sf input to fgen
01854          call LINEAR_INTERP(specinterp(i)%f,specinterp(i)%Sf,specinterp(i)%nf,wp%fgen(ii),wp%vargenq(i)%Sf(ii),dummy)
01855       enddo
01856       wp%vargenq(i)%Sf = min(wp%vargen(i)%Sf,wp%vargenq(i)%Sf)
01857    enddo
01858 
01859 end subroutine generate_wave_train_variance
01860 
01861 ! --------------------------------------------------------------
01862 ! ------ Calculate amplitudes at each spectrum location --------
01863 ! ------------ for every wave train component ------------------
01864 subroutine generate_wave_train_properties_per_offshore_point(wp,s)
01865 
01866    use spaceparams
01867    use interp
01868 
01869    implicit none
01870    ! input/output
01871    type(waveparamsnew),intent(inout)            :: wp
01872    type(spacepars),intent(in)                   :: s
01873    ! internal
01874    integer                                      :: i,ii,dummy
01875    integer,dimension(2)                         :: interpindex
01876    real*8,dimension(2)                          :: positions,sf
01877    logical                                      :: interpcase
01878    real*8                                       :: here,sfnow,sfimp
01879    integer,dimension(size(n_index_loc))         :: temp_index_loc
01880 
01881    ! allocate space for the amplitude array and representative integration angle
01882    allocate(wp%A(s%ny+1,wp%K))
01883    !    allocate(wp%danggen(s%ny+1))
01884    allocate(wp%Sfinterp(s%ny+1,wp%K))
01885    allocate(wp%Sfinterpq(s%ny+1,wp%K))
01886    allocate(wp%Hm0interp(s%ny+1))
01887 
01888    ! where necessary, interpolate Sf of each spectrum location
01889    ! to the current grid cell, and use this to calculate A
01890    do i=1,s%ny+1
01891       ! Four possibilities:
01892       ! 1: this exact point has an input spectrum
01893       ! 2: this point lies between two input spectra
01894       ! 3: this point lies before any input spectrum
01895       ! 4: this point lies beyond any input spectrum
01896       if (any(n_index_loc==i)) then  ! case 1
01897          interpcase = .false.
01898          do ii=1,nspectra
01899             if(n_index_loc(ii)==i) then
01900                interpindex = ii
01901             endif
01902          enddo
01903       elseif(i<minval(n_index_loc)) then   ! case 3
01904          interpcase = .false.
01905          do ii=1,nspectra
01906             if(n_index_loc(ii)==minval(n_index_loc)) then
01907                interpindex = ii
01908             endif
01909          enddo
01910       elseif(i>maxval(n_index_loc)) then   ! case 4
01911          interpcase = .false.
01912          do ii=1,nspectra
01913             if(n_index_loc(ii)==maxval(n_index_loc)) then
01914                interpindex = ii
01915             endif
01916          enddo
01917       else   ! case 2
01918          interpcase = .true.
01919          temp_index_loc = n_index_loc
01920          where(n_index_loc>i)
01921             temp_index_loc = -huge(0)
01922          endwhere
01923          interpindex(1) = minval(maxloc(temp_index_loc))
01924 
01925          temp_index_loc = n_index_loc
01926          where(n_index_loc<i)
01927             temp_index_loc = huge(0)
01928          endwhere
01929          interpindex(2) = minval(minloc(temp_index_loc))
01930       endif
01931 
01932       ! interpolate Sf
01933       if (interpcase) then
01934          positions(1) = s%ndist(1,n_index_loc(interpindex(1)))
01935          positions(2) = s%ndist(1,n_index_loc(interpindex(2)))
01936          here = s%ndist(1,i)
01937          do ii=1,wp%K
01938             sf(1) = wp%vargen(interpindex(1))%Sf(ii)
01939             sf(2) = wp%vargen(interpindex(2))%Sf(ii)
01940             call LINEAR_INTERP(positions,sf,2,here,wp%Sfinterp(i,ii),dummy)
01941             sf(1) = wp%vargenq(interpindex(1))%Sf(ii)
01942             sf(2) = wp%vargenq(interpindex(2))%Sf(ii)
01943             call LINEAR_INTERP(positions,sf,2,here,wp%Sfinterpq(i,ii),dummy)
01944          enddo
01945          ! Ensure that the total amount of variance has not been reduced/increased
01946          ! during interpolation for short wave energy only. This is not done for
01947          ! Sf for bound long wave generation
01948          sfnow = sum(wp%Sfinterp(i,:))  ! integration over fixed bin df size unnecessary
01949          sf(1) = sum(wp%vargen(interpindex(1))%Sf)
01950          sf(2) = sum(wp%vargen(interpindex(2))%Sf)
01951          call LINEAR_INTERP(positions,sf,2,here,sfimp,dummy)
01952          wp%Sfinterp(i,:)=wp%Sfinterp(i,:)*sfimp/sfnow
01953       else
01954          wp%Sfinterp(i,:) = wp%vargen(interpindex(1))%Sf
01955          wp%Sfinterpq(i,:) = wp%vargenq(interpindex(1))%Sf
01956       endif
01957 
01958       wp%A(i,:) = sqrt(2*wp%Sfinterp(i,:)*wp%dfgen)
01959 
01960       wp%Hm0interp(i) = 4*sqrt(sum(wp%Sfinterp(i,:))*wp%dfgen)
01961 
01962    enddo ! i=1,s%ny+1
01963 
01964 end subroutine generate_wave_train_properties_per_offshore_point
01965 
01966 ! --------------------------------------------------------------
01967 ! --------- Calculate Fourier componets for each wave ----------
01968 ! ---------- train component on the offshore boundary ----------
01969 subroutine generate_wave_train_Fourier(wp)
01970 
01971 #ifdef BUILDXBEACH
01972    use interp
01973    use logging_module
01974 #endif
01975    use math_tools
01976    use wave_boundary_datastore
01977 
01978    implicit none
01979    ! input/output
01980    type(waveparamsnew),intent(inout)            :: wp
01981    ! internal
01982    integer                                      :: i,ii,tempi
01983    complex(fftkind),dimension(:),allocatable    :: tempcmplx
01984 
01985    ! Determine indices of wave train components in frequency axis and
01986    ! Fourier transform result
01987    allocate(wp%Findex(wp%K))
01988    tempi = floor(wp%fgen(1)/wp%dfgen)
01989    do i=1,wp%K
01990       wp%Findex(i) = tempi + i
01991    enddo
01992 
01993    ! Allocate Fourier coefficients for each y-position at the offshore boundary and
01994    ! each time step
01995    allocate(wp%CompFn(npb,wp%tslen))
01996    wp%CompFn=0.d0
01997    allocate(tempcmplx(wp%tslen/2-1))
01998 #ifdef BUILDXBEACH
01999    call writelog('ls','','Calculating Fourier components')
02000    call progress_indicator(.true.,0.d0,5.d0,2.d0)
02001 #endif
02002    do i=1,wp%K
02003 #ifdef BUILDXBEACH
02004       call progress_indicator(.false.,dble(i)/wp%K*100,5.d0,2.d0)
02005 #endif
02006       do ii=1,npb
02007          ! Determine first half of complex Fourier coefficients of wave train
02008          ! components using random phase and amplitudes from sampled spectrum
02009          ! until Nyquist frequency. The amplitudes are represented in a
02010          ! two-sided spectrum, which results in the factor 1/2.
02011          ! Unroll Fourier components along offshore boundary, assuming all wave trains
02012          ! start at x(1,1), y(1,1).
02013          wp%CompFn(ii,wp%Findex(i)) = wp%A(ii,i)/2*exp(par_compi*wp%phigen(i))* &    ! Bas: wp%Findex used in time dimension because t=j*dt in frequency space
02014          exp(-par_compi*wp%kgen(i)* &
02015          (dsin(wp%thetagen(i))*(waveBoundaryParameters%yb(ii)-waveBoundaryParameters%y0) &
02016          +dcos(wp%thetagen(i))*(waveBoundaryParameters%xb(ii)-waveBoundaryParameters%x0)) )
02017 
02018          ! Determine Fourier coefficients beyond Nyquist frequency (equal to
02019          ! coefficients at negative frequency axis) of relevant wave components for
02020          ! first y-coordinate by mirroring
02021          tempcmplx = conjg(wp%CompFn(ii,2:wp%tslen/2))
02022          tempcmplx = flipiv(tempcmplx,size(tempcmplx))
02023          wp%CompFn(ii,wp%tslen/2+2:wp%tslen)=tempcmplx
02024       enddo
02025    enddo
02026 
02027    ! Free memory
02028    deallocate(tempcmplx)
02029 
02030 end subroutine generate_wave_train_Fourier
02031 
02032 ! --------------------------------------------------------------
02033 ! --------- Calculate in which computational wave bin ----------
02034 ! ------------- each wave train component belongs --------------
02035 subroutine distribute_wave_train_directions(wp,nspr)
02036 
02037 #ifdef BUILDXBEACH
02038    use logging_module
02039 #endif
02040    use wave_boundary_datastore
02041 
02042    implicit none
02043 
02044    ! input/output
02045    type(waveparamsnew),intent(inout)            :: wp
02046    integer,intent(in)                           :: nspr
02047    ! internal
02048    integer                                      :: i,ii,itheta
02049    real*8,dimension(:,:),allocatable            :: binedges
02050    logical                                      :: toosmall,toolarge
02051    real*8                                       :: lostvar,keptvar,perclost
02052    integer                                      :: lntheta              ! local copies that can be changed without
02053    real*8                                       :: ldtheta              ! damage to the rest of the model
02054    real*8                                       :: dang
02055 
02056    ! Calculate the bin edges of all the computational wave bins in the
02057    ! XBeach model (not the input spectrum)
02058    allocate(binedges(lntheta,2))
02059    do itheta=1,lntheta
02060       binedges(itheta,1) = mod(waveBoundaryParameters%theta(itheta)-ldtheta/2,2*par_pi)
02061       binedges(itheta,2) = mod(waveBoundaryParameters%theta(itheta)+ldtheta/2,2*par_pi)
02062    enddo
02063 
02064    ! All generated wave components are in the rang 0<=theta<2pi.
02065    ! We link wave components to a wave direction bin if the direction falls
02066    ! within the bin boundaries. Note the >= and <=, ranther than >= and <. This
02067    ! is not necessarily a problem, but solves having to make an exception for the
02068    ! highest wave direction bin, in which >= and <= should be applicable.
02069    ! In the case of a central bin and a wave direction exactly (!) on the bin
02070    ! interface, the wave will be linked to the first wave bin in the ordering,
02071    ! rather than the higher of the two bins.
02072    !
02073    ! Initially set WDindex to zero. This marks a wave direction outside the
02074    ! computational wave bins. In case it does not fit in a directional wave
02075    ! bin, it remains zero at the end of the loops.
02076    ! Note: this does not ensure all energy is included in the wave bins,
02077    ! as wave energy may still fall outside the computational domain.
02078    wp%WDindex = 0
02079    do i=1,wp%K
02080       do itheta=1,lntheta
02081          ! special case if this bin spans 0 degrees
02082          if (binedges(i,1)>binedges(i,2)) then
02083             ! Need to check both above and below zero degrees
02084             if((wp%thetagen(i)>=binedges(itheta,1) .and. wp%thetagen(i)<=2*par_px) .or. &
02085             (wp%thetagen(i)>=0.d0 .and. wp%thetagen(i)<=binedges(itheta,2)    ) ) then
02086                wp%WDindex(i) = itheta
02087                ! We now have the correct wave bin, move to next wave component K
02088                exit
02089             endif
02090          else
02091             if(wp%thetagen(i)>=binedges(itheta,1) .and. wp%thetagen(i)<=binedges(itheta,2)) then
02092                wp%WDindex(i) = itheta
02093                ! We now have the correct wave bin, move to next wave component K
02094                exit
02095             endif
02096          endif
02097       enddo
02098    enddo
02099 
02100    ! If the user has set nspr == 1 then the randomly drawn wave directions
02101    ! should be set to the centres of the wave directional bins.
02102    ! Also move all wave energy falling outside the computational bins, into
02103    ! the computational domain (in the outer wave direction bins)
02104    if (nspr==1) then
02105       do i=1,wp%K
02106          if (wp%WDindex(i)>0) then
02107             ! reset the direction of this wave train to the centre of the bin
02108             wp%thetagen(i)=waveBoundaryParameters%theta(wp%WDindex(i))
02109          endif
02110       enddo
02111    endif
02112 
02113    ! Check the amount of energy lost to wave trains falling outside the computational
02114    ! domain
02115    lostvar = 0.d0
02116    keptvar = 0.d0
02117    do i=1,wp%K
02118       if (wp%WDindex(i)==0) then
02119          lostvar = lostvar + sum(wp%A(:,i)**2)
02120       else
02121          keptvar = keptvar + sum(wp%A(:,i)**2)
02122       endif
02123    enddo
02124    perclost = 100*(lostvar/(lostvar+keptvar))
02125 #ifdef BUILDXBEACH
02126    if (perclost>5.0d0) then
02127       call writelog('lsw','(a,f0.1,a)','Large amounts of energy (',perclost, &
02128       '%) fall outside computational domain at the offshore boundary')
02129       call writelog('lsw','','Check specification of input wave angles and wave directional grid')
02130    else
02131       call writelog('ls','(a,f0.1,a)','Wave energy outside computational domain at offshore boundary: ',perclost,'%')
02132    endif
02133 #endif
02134    ! Free memory
02135    deallocate(binedges)
02136 
02137 end subroutine distribute_wave_train_directions
02138 
02139 ! --------------------------------------------------------------
02140 ! --------- Calculate energy envelope time series from ---------
02141 ! -------- Fourier components, and write to output file --------
02142 subroutine generate_ebcf(wp)
02143 
02144 
02145 #ifdef BUILDXBEACH
02146    use interp
02147    use logging_module
02148 #endif
02149    use math_tools
02150 
02151    implicit none
02152 
02153    ! input/output
02154    type(waveparamsnew),intent(inout)            :: wp
02155    ! internal
02156    integer                                      :: itheta,iy,iwc,it,irec
02157    integer                                      :: index,status
02158    integer                                      :: reclen,fid
02159    integer,dimension(:),allocatable             :: nwc
02160    real*8,dimension(:,:,:), allocatable         :: zeta, Ampzeta, E_tdir, E_interp
02161    real*8,dimension(:,:), allocatable           :: eta, Amp
02162    complex(fftkind),dimension(:),allocatable    :: Gn, tempcmplx,tempcmplxhalf
02163    integer,dimension(:),allocatable             :: tempindex,tempinclude
02164    real*8                                       :: stdzeta,stdeta,etot,perc
02165 
02166 
02167    ! Allocate variables for water level exitation and amplitude with and without
02168    ! directional spreading dependent envelope
02169    allocate(zeta(npb,wp%tslen,ntheta))
02170    allocate(Ampzeta(npb,wp%tslen,ntheta))
02171    zeta=0.d0
02172    Ampzeta=0.d0
02173 
02174    allocate(eta(npb,wp%tslen))
02175    allocate(Amp(npb,wp%tslen))
02176    eta=0.d0
02177    Amp=0.d0
02178 
02179    ! Calculate wave energy for each y-coordinate along seaside boundary for
02180    ! current computational directional bin
02181    allocate(nwc(ntheta))
02182    allocate(Gn(wp%tslen))
02183    allocate(tempinclude(wp%K))
02184    allocate(tempcmplx(wp%tslen))
02185    allocate(tempcmplxhalf(size(Gn(wp%tslen/2+2:wp%tslen))))
02186    do itheta=1,ntheta
02187 #ifdef BUILDXBEACH
02188       call writelog('ls','(A,I0,A,I0)','Calculating short wave time series for theta bin ',itheta,' of ',s%ntheta)
02189 #endif
02190       ! Select wave components that are in the current computational
02191       ! directional bin
02192       tempinclude=0
02193       where (wp%WDindex==itheta)
02194          tempinclude=1
02195       end where
02196 
02197       ! Determine number of wave components that are in the current
02198       ! computational directional bin
02199       nwc(itheta)=sum(tempinclude)
02200 
02201       ! Determine for each wave component in the current computational
02202       ! directional bin its index in the Fourier coefficients array
02203       ! ordered from high to low frequency
02204       allocate(tempindex(nwc(itheta)))
02205       tempindex=0
02206       do iwc=1,nwc(itheta)
02207          ! find highest
02208          index=maxval(maxloc(tempinclude))
02209          ! reset that one so that the next highest in found in next iteration
02210          tempinclude(index)=0
02211          tempindex(iwc)=wp%Findex(index)
02212       end do
02213 
02214       ! Check whether any wave components are in the current computational
02215       ! directional bin
02216       if (nwc(itheta)>0) then
02217          do iy=1,npb
02218             ! Reset
02219             Gn=0
02220 
02221             ! Determine Fourier coefficients of all wave components for current
02222             ! y-coordinate in the current computational directional bin
02223             Gn(tempindex)=wp%CompFn(iy,tempindex)
02224             tempcmplxhalf = conjg(Gn(2:wp%tslen/2))
02225             call flipiv(tempcmplxhalf,size(tempcmplxhalf))
02226             Gn(wp%tslen/2+2:wp%tslen)=tempcmplxhalf
02227 
02228             ! Inverse Discrete Fourier transformation to transform back to time
02229             ! domain from frequency domain
02230             tempcmplx=Gn
02231             status=0
02232             tempcmplx=fft(tempcmplx,inv=.true.,stat=status)
02233 
02234             ! Scale result
02235             tempcmplx=tempcmplx/sqrt(dble(size(tempcmplx)))
02236 
02237             ! Superimpose gradual increase and decrease of energy input for
02238             ! current y-coordinate and computational diretional bin on
02239             ! instantaneous water level excitation
02240             !
02241             ! Robert: use final wave elevation from last iteration to startup
02242             ! this boundary condition
02243             zeta(iy,:,itheta)=dble(tempcmplx*wp%tslen)
02244             ! The first time this function is called in a simulation, lastwaveelevation is unknown,
02245             ! so would be set to zero. However, this artificially increases the taper time, and is
02246             ! not useful if repeatwbc = .true., as this zero level is repeated every boundary condition
02247             ! Instead, we select zeta at the end of the first boundary condition time series to
02248             ! initialise lastwaveelevation
02249             if (bccount==0) then
02250                lastwaveelevation(:,itheta) = zeta(iy,ind_end_taper,itheta)
02251             endif
02252             zeta(iy,:,itheta)=zeta(iy,:,itheta)*wp%taperw+(1-wp%taperw)*lastwaveelevation(iy,itheta)
02253             ! note that taperw is only zero at the start, not the end of the time series, so we
02254             ! can safely copy zeta at the point in time where t=rtbc to lastwaveelevation for use
02255             ! in the generation of the next time series
02256             lastwaveelevation(:,itheta) = zeta(iy,ind_end_taper,itheta)
02257          enddo ! iy=1,ny+1
02258       endif  ! nwc>0
02259       deallocate(tempindex)
02260    enddo ! itheta = 1,ntheta
02261    deallocate(tempinclude)
02262    deallocate(Gn)
02263    deallocate(tempcmplxhalf)
02264    !
02265    ! Calculate energy envelope amplitude
02266 
02267    ! Robert: note oldwbc has been removed
02268    do iy=1,npb
02269       ! Integrate instantaneous water level excitation of wave
02270       ! components over directions
02271       eta(iy,:) = sum(zeta(iy,:,:),2)
02272       tempcmplx=eta(iy,:)
02273 
02274       ! Hilbert transformation to determine envelope of all total
02275       ! non-directional wave components
02276       call hilbert(tempcmplx,size(tempcmplx))
02277 
02278       ! Determine amplitude of water level envelope by calculating
02279       ! the absolute value of the complex wave envelope descriptions
02280       Amp(iy,:)=abs(tempcmplx)
02281 
02282       ! Calculate standard deviation of non-directional
02283       ! instantaneous water level excitation of all
02284       ! wave components to be used as weighing factor
02285       stdeta = sqrt(sum(eta(iy,:)**2)/(size(eta(iy,:))-1))
02286       do itheta=1,ntheta
02287          if (nwc(itheta)>0) then
02288             ! Calculate standard deviations of directional
02289             ! instantaneous water level excitation of all
02290             ! wave components to be used as weighing factor
02291             stdzeta = sqrt(sum(zeta(iy,:,itheta)**2)/(size(zeta(iy,:,itheta))-1))
02292 
02293             ! Calculate amplitude of directional wave envelope
02294             Ampzeta(iy,:,itheta)= Amp(iy,:)*stdzeta/stdeta
02295          else  !  nwc==0
02296             ! Current computational directional bin does not contain any wave
02297             ! components
02298             Ampzeta(iy,:,itheta)=0.d0
02299          endif  ! nwc>0
02300       end do   ! 1:ntheta
02301       ! Print status message to screen
02302 #ifdef BUILDXBEACH
02303       call writelog('ls','(A,I0,A,I0,A)','Y-point ',iy,' of ',s%ny+1,' done.')
02304 #endif
02305    end do   ! 1:ny+1
02306    !
02307 
02308    ! free memory
02309    deallocate(tempcmplx)
02310    deallocate(nwc)
02311 
02312    ! Allocate memory for energy time series
02313    allocate(E_tdir(npb,wp%tslen,ntheta))
02314    E_tdir=0.0d0
02315    E_tdir=0.5d0*waveBoundaryParameters%rho*par_g*Ampzeta**2
02316    E_tdir=E_tdir/waveBoundaryParameters%dtheta
02317 
02318    ! Print directional energy distribution to screen
02319    etot = sum(E_tdir)
02320    do itheta=1,ntheta
02321       perc = sum(E_tdir(:,:,itheta))/etot*100
02322 #ifdef BUILDXBEACH
02323       call writelog('ls','(a,i0,a,f0.2,a)','Wave bin ',itheta,' contains ',perc,'% of total energy')
02324 #endif
02325    enddo
02326    !
02327    !
02328    ! Store time series in internal memory
02329    !
02330    ! First deallocate arrays if necessary
02331    if (allocated(waveBoundaryTimeSeries%eebct)) deallocate(waveBoundaryTimeSeries%eebct)
02332    if (allocated(waveBoundaryTimeSeries%tbc)) deallocate(waveBoundaryTimeSeries%tbc)
02333    !
02334    ! Allocate in the correct size
02335    allocate(waveBoundaryTimeSeries%eebct(npb,wp%tslenbc+2,ntheta))
02336    allocate(waveBoundaryTimeSeries%tbc(wp%tslenbc+2))
02337    !
02338    ! Store time vector
02339    do it=2,wp%tslenbc+1
02340       waveBoundaryTimeSeries%tbc(2:wp%tslenbc+1) = (it-2)*wp%dtbc + waveBoundaryAdministration%startCurrentSeries
02341    enddo
02342    ! add 'inifinite ends to the time series in case of mismatch at the end or start of the time
02343    ! series generation and interpolation at each time step
02344    waveBoundaryTimeSeries%tbc(1) = -1.d0*huge(0.d0)
02345    waveBoundaryTimeSeries%tbc(wp%tslenbc+2) = 1.d0*huge(0.d0)
02346    if (wp%dtchanged) then
02347       ! Interpolate from internal time axis to output time axis
02348       do itheta=1,ntheta
02349          do it=2,wp%tslenbc+1
02350             do iy=1,npb
02351                call linear_interp(wp%tin,E_tdir(iy,:,itheta),wp%tslen, &
02352                (it-1)*wp%dtbc,waveBoundaryTimeSeries%eebct(iy,it,itheta),status)
02353             enddo
02354          enddo
02355       enddo
02356    else
02357       ! no need for interpolation
02358       waveBoundaryTimeSeries%eebct(:,2:wp%tslenbc+1,:) = E_tdir
02359    endif
02360    !
02361    ! add 'inifinite ends to the time series in case of mismatch at the end or start of the time
02362    ! series generation and interpolation at each time step
02363    waveBoundaryTimeSeries%eebct(:,1,:) = waveBoundaryTimeSeries%eebct(:,2,:)
02364    waveBoundaryTimeSeries%eebct(:,wp%tslenbc+2,:) = waveBoundaryTimeSeries%eebct(:,wp%tslenbc+1,:)
02365    !
02366    !
02367    ! Free memory
02368    deallocate(zeta,Ampzeta,E_tdir, Amp, eta)
02369 
02370 end subroutine generate_ebcf
02371 
02372 
02373 ! --------------------------------------------------------------
02374 ! ------ Calculate time series of short wave at offshore -------
02375 ! --------------------------- boundary -------------------------
02376 subroutine generate_swts(wp)
02377 #ifdef BUILDXBEACH
02378    use logging_module
02379 #endif
02380    use wave_boundary_datastore
02381 
02382    implicit none
02383 
02384    ! input/output
02385    type(waveparamsnew),intent(inout)            :: wp
02386    ! internal
02387    integer                                      :: j,it,ik
02388    real*8,dimension(npb)                        :: distx,disty
02389 
02390    ! allocate memory for time series of data
02391    allocate(wp%zsits(npb,wp%tslen))
02392    allocate(wp%uits(npb,wp%tslen))
02393    wp%zsits=0.d0
02394    wp%uits=0.d0
02395    ! distance of each grid point to reference point
02396    do j=1,npb
02397       distx(j) = waveBoundaryParameters%xb(j)-waveBoundaryParameters%x0
02398       disty(j) = waveBoundaryParameters%yb(j)-waveBoundaryParameters%y0
02399    enddo
02400    !
02401    ! total surface elevation
02402 #ifdef BUILDXBEACH
02403    call writelog('ls','','Calculating short wave elevation time series')
02404    call progress_indicator(.true.,0.d0,5.d0,2.d0)
02405 #endif
02406    do it=1,wp%tslen
02407 #ifdef BUILDXBEACH
02408       call progress_indicator(.false.,dble(it)/wp%tslen*100,5.d0,2.d0)
02409 #endif
02410       do ik=1,wp%K
02411          do j=1,npb
02412             wp%zsits(j,it)=wp%zsits(j,it)+wp%A(j,ik)*dsin( &
02413             +wp%wgen(ik)*wp%tin(it)&
02414             -wp%kgen(ik)*( dsin(wp%thetagen(ik))*disty(j) &
02415             +dcos(wp%thetagen(ik))*distx(j) &
02416             ) &
02417             +wp%phigen(ik) &
02418             )
02419          enddo
02420       enddo
02421    enddo
02422    ! depth-averaged velocity
02423 #ifdef BUILDXBEACH
02424    call writelog('ls','','Calculating short wave velocity time series')
02425    call progress_indicator(.true.,0.d0,5.d0,2.d0)
02426 #endif
02427    do it=1,wp%tslen
02428 #ifdef BUILDXBEACH
02429       call progress_indicator(.false.,dble(it)/wp%tslen*100,5.d0,2.d0)
02430 #endif
02431       do ik=1,wp%K
02432          do j=1,npb
02433             wp%uits(j,it) = wp%uits(j,it) + &
02434             1.d0/hb0*wp%wgen(ik)*wp%A(j,ik)/sinh(wp%kgen(ik)*hb0) * &
02435             dsin( &
02436             +wp%wgen(ik)*wp%tin(it)&
02437             -wp%kgen(ik)*( dsin(wp%thetagen(ik))*disty(j) &
02438             +dcos(wp%thetagen(ik))*distx(j) &
02439             ) &
02440             +wp%phigen(ik) &
02441             ) * &
02442             1.d0/wp%kgen(ik)*sinh(wp%kgen(ik)*hb0)
02443 
02444          enddo
02445       enddo
02446    enddo
02447    !
02448    !
02449    ! Apply tapering to time series
02450    do j=1,npb
02451       wp%uits(j,:)=wp%uits(j,:)*wp%taperf
02452       wp%zsits(j,:)=wp%zsits(j,:)*wp%taperf
02453    enddo
02454 end subroutine generate_swts
02455 
02456 
02457 ! --------------------------------------------------------------
02458 ! ----------------------- Bound long wave ----------------------
02459 ! --------------------------------------------------------------
02460 subroutine generate_qbcf(wp)
02461 
02462 #ifdef BUILDXBEACH
02463    use logging_module
02464    use interp
02465 #endif
02466    use math_tools
02467    use wave_boundary_datastore
02468 
02469    implicit none
02470 
02471    ! input/output
02472    type(waveparamsnew),intent(inout)            :: wp
02473    ! internal
02474    integer                                      :: j,m,iq,irec,it  ! counters
02475    integer                                      :: K               ! copy of K
02476    integer                                      :: halflen,reclen,fid,status
02477    logical                                      :: firsttime    ! used for output message only
02478    real*8                                       :: deltaf       ! difference frequency
02479    real*8,dimension(:), allocatable             :: term1,term2,term2new,dif,chk1,chk2
02480    real*8,dimension(npb)                        :: distx,disty
02481    real*8,dimension(:,:),allocatable            :: Eforc,D,deltheta,KKx,KKy,dphi3,k3,cg3,theta3,Abnd
02482    real*8,dimension(:,:,:),allocatable          :: q,qinterp
02483    complex(fftkind),dimension(:),allocatable    :: Comptemp,Comptemp2,Gn
02484    complex(fftkind),dimension(:,:,:),allocatable:: Ftemp
02485 
02486 
02487 
02488    ! This function has changed with respect to previous versions of XBeach, in that
02489    ! the bound long wave has to be calculated separately at each longshore point,
02490    ! owing to longshore varying incident wave spectra
02491 
02492    ! shortcut variable
02493    K = wp%K
02494 
02495    ! Print message to screen
02496 #ifdef BUILDXBEACH
02497    call writelog('sl','', 'Calculating primary wave interaction')
02498 #endif
02499 
02500    ! Allocate two-dimensional variables for all combinations of interacting wave
02501    ! components to be filled triangular
02502    allocate(Eforc(K-1,K))
02503    allocate(D(K-1,K))
02504    allocate(deltheta(K-1,K))
02505    allocate(KKx(K-1,K))
02506    allocate(KKy(K-1,K))
02507    allocate(dphi3(K-1,K))
02508    allocate(k3(K-1,K))
02509    allocate(cg3(K-1,K))
02510    allocate(theta3(K-1,K))
02511    ! Allocate variables for amplitude and Fourier coefficients of bound long wave
02512    allocate(Gn(wp%tslen))
02513    allocate(Abnd(K-1,K))
02514    allocate(Ftemp(K-1,K,3)) ! Jaap qx, qy, zeta
02515    ! Storage for output discharge
02516    allocate(q(s%ny+1,wp%tslen,4))   ! qx qy qtot, zeta
02517    !
02518    ! Initialize variables as zero
02519    Eforc = 0
02520    D = 0
02521    deltheta = 0
02522    KKx = 0
02523    KKy = 0
02524    dphi3 = 0
02525    k3 = 0
02526    cg3 = 0
02527    theta3 = 0
02528    Gn = 0*par_compi
02529    Abnd = 0
02530    Ftemp = 0*par_compi
02531    q = 0
02532 
02533    ! First time is set true for each time new wave bc are generated
02534    firsttime = .true.
02535 
02536    ! upper half of frequency space
02537    halflen = wp%tslen/2
02538 
02539    ! Run loop over wave-wave interaction components
02540 #ifdef BUILDXBEACH
02541    call progress_indicator(.true.,0.d0,5.d0,2.d0)
02542 #endif
02543    do m=1,K-1
02544 #ifdef BUILDXBEACH
02545       call progress_indicator(.false.,dble(m)/(K-1)*100,5.d0,2.d0)
02546 #endif
02547       ! Allocate memory
02548       allocate(term1(K-m),term2(K-m),term2new(K-m),dif(K-m),chk1(K-m),chk2(K-m))
02549 
02550       ! Determine difference frequency
02551       deltaf=m*wp%dfgen
02552 
02553       ! Determine difference angles (pi already added)
02554       deltheta(m,1:K-m) = abs(wp%thetagen(m+1:K)-wp%thetagen(1:K-m))+par_pi
02555 
02556       ! Determine x- and y-components of wave numbers of difference waves
02557       KKy(m,1:K-m)=wp%kgen(m+1:K)*dsin(wp%thetagen(m+1:K))-wp%kgen(1:K-m)*dsin(wp%thetagen(1:K-m))
02558       KKx(m,1:K-m)=wp%kgen(m+1:K)*dcos(wp%thetagen(m+1:K))-wp%kgen(1:K-m)*dcos(wp%thetagen(1:K-m))
02559 
02560       ! Determine difference wave numbers according to Van Dongeren et al. 2003
02561       ! eq. 19
02562       k3(m,1:K-m) =sqrt(wp%kgen(1:K-m)**2+wp%kgen(m+1:K)**2+ &
02563       2*wp%kgen(1:K-m)*wp%kgen(m+1:K)*dcos(deltheta(m,1:K-m)))
02564 
02565       ! Determine group velocity of difference waves
02566       cg3(m,1:K-m)= 2.d0*par_pi*deltaf/k3(m,1:K-m)
02567 
02568       ! Modification Robert + Jaap: make sure that the bound long wave amplitude does not
02569       !                             explode when offshore boundary is too close to shore,
02570       !                             by limiting the interaction group velocity
02571       cg3(m,1:K-m) = min(cg3(m,1:K-m),waveBoundaryParameters%nmax*sqrt(par_g/k3(m,1:K-m)*tanh(k3(m,1:K-m)*hb0)))
02572 
02573       ! Determine difference-interaction coefficient according to Herbers 1994
02574       ! eq. A5
02575       term1 = (-wp%wgen(1:K-m))*wp%wgen(m+1:K)
02576       term2 = (-wp%wgen(1:K-m))+wp%wgen(m+1:K)
02577       term2new = cg3(m,1:K-m)*k3(m,1:K-m)
02578       dif = (abs(term2-term2new))
02579       if (any(dif>0.01*term2) .and. firsttime) then
02580          firsttime = .false.
02581       endif
02582       chk1  = cosh(wp%kgen(1:K-m)*hb0)
02583       chk2  = cosh(wp%kgen(m+1:K)*hb0)
02584 
02585       D(m,1:K-m) = -par_g*wp%kgen(1:K-m)*wp%kgen(m+1:K)*dcos(deltheta(m,1:K-m))/2.d0/term1+par_g*term2*(chk1*chk2)/ &
02586       ((par_g*k3(m,1:K-m)*tanh(k3(m,1:K-m)*hb0)-(term2new)**2)*term1*cosh(k3(m,1:K-m)*hb0))* &
02587       (term2*((term1)**2/par_g/par_g - wp%kgen(1:K-m)*wp%kgen(m+1:K)*dcos(deltheta(m,1:K-m))) &
02588       - 0.50d0*((-wp%wgen(1:K-m))*wp%kgen(m+1:K)**2/(chk2**2)+wp%wgen(m+1:K)*wp%kgen(1:K-m)**2/(chk1**2)))
02589 
02590       ! Correct for surface elevation input and output instead of bottom pressure
02591       ! so it is consistent with Van Dongeren et al 2003 eq. 18
02592       D(m,1:K-m) = D(m,1:K-m)*cosh(k3(m,1:K-m)*hb0)/(cosh(wp%kgen(1:K-m)*hb0)*cosh(wp%kgen(m+1:K)*hb0))
02593 
02594       ! Exclude interactions with components smaller than or equal to current
02595       ! component according to lower limit Herbers 1994 eq. 1
02596       where(wp%fgen<=deltaf) D(m,:)=0.d0
02597 
02598       ! Exclude interactions with components that are cut-off by the fcutoff
02599       ! parameter
02600       if (deltaf<=waveBoundaryParameters%fcutoff) D(m,:)=0.d0
02601 
02602       ! Determine phase of bound long wave assuming a local equilibrium with
02603       ! forcing of interacting primary waves according to Van Dongeren et al.
02604       ! 2003 eq. 21 (the angle is the imaginary part of the natural log of a
02605       ! complex number as long as the complex number is not zero)
02606       allocate(Comptemp(K-m),Comptemp2(K-m))
02607       Comptemp=conjg(wp%CompFn(1,wp%Findex(1)+m:wp%Findex(1)+K-1))
02608       Comptemp2=conjg(wp%CompFn(1,wp%Findex(1):wp%Findex(1)+K-m-1))
02609       dphi3(m,1:K-m) = par_pi+imag(log(Comptemp))-imag(log(Comptemp2))
02610       deallocate (Comptemp,Comptemp2)
02611       !
02612       ! Determine angle of bound long wave according to Van Dongeren et al. 2003 eq. 22
02613       theta3 = atan2(KKy,KKx)
02614       !
02615       ! free memory
02616       deallocate(term1,term2,term2new,dif,chk1,chk2)
02617    enddo ! m=1,K-1
02618    !
02619    ! Output to screen
02620 #ifdef BUILDXBEACH
02621    if (.not. firsttime) then
02622       call writelog('lws','','Warning: shallow water so long wave variance is reduced using par%nmax')
02623    endif
02624    call writelog('sl','', 'Calculating flux at boundary')
02625 #endif
02626    !
02627    ! Allocate temporary arrays for upcoming loop
02628    allocate(Comptemp(halflen-1))
02629    allocate(Comptemp2(wp%tslen))
02630    !
02631    !
02632    ! distance of each grid point to reference point
02633    do j=1,npb
02634       distx(j) = waveBoundaryParameters%xb(j)-waveBoundaryParameters%x0
02635       disty(j) = waveBoundaryParameters%yb(j)-waveBoundaryParameters%y0
02636    enddo
02637    !
02638    ! Run a loop over the offshore boundary
02639    do j=1,npb
02640       ! Determine energy of bound long wave according to Herbers 1994 eq. 1 based
02641       ! on difference-interaction coefficient and energy density spectra of
02642       ! primary waves
02643       ! Robert: E = 2*D**2*S**2*dtheta**2*df can be rewritten as
02644       !         E = 2*D**2*Sf**2*df
02645       Eforc = 0
02646       do m=1,K-1
02647          Eforc(m,1:K-m) = 2*D(m,1:K-m)**2*wp%Sfinterpq(j,1:K-m)*wp%Sfinterpq(j,m+1:K)*wp%dfgen
02648       enddo
02649       !
02650       ! Calculate bound wave amplitude for this offshore grid point
02651       Abnd = sqrt(2*Eforc*wp%dfgen)
02652       !
02653       ! Determine complex description of bound long wave per interaction pair of
02654       ! primary waves for first y-coordinate along seaside boundary
02655       Ftemp(:,:,1) = Abnd/2*exp(-1*par_compi*dphi3)*cg3*dcos(theta3) ! qx
02656       Ftemp(:,:,2) = Abnd/2*exp(-1*par_compi*dphi3)*cg3*dsin(theta3) ! qy
02657       !Ftemp(:,:,3) = Abnd/2*exp(-1*par_compi*dphi3)*cg3              ! qtot
02658       Ftemp(:,:,3) = Abnd/2*exp(-1*par_compi*dphi3)                  ! eta
02659       !
02660       ! loop over qx,qy and qtot
02661       do iq=1,3
02662          ! Unroll wave component to correct place along the offshore boundary
02663          Ftemp(:,:,iq) = Ftemp(:,:,iq)* &
02664          exp(-1*par_compi*(KKy*disty+KKx*distx))
02665          ! Determine Fourier coefficients
02666          Gn(2:K) = sum(Ftemp(:,:,iq),DIM=2)
02667          Comptemp = conjg(Gn(2:halflen))
02668          call flipiv(Comptemp,halflen-1)
02669          Gn(halflen+2:wp%tslen) = Comptemp
02670          !
02671          ! Print status message to screen
02672 #ifdef BUILDXBEACH
02673          if (iq==3) then
02674             call writelog('ls','(A,I0,A,I0)','Flux ',j,' of ',s%ny+1)
02675          endif
02676 #endif
02677          !
02678          ! Inverse Discrete Fourier transformation to transform back to time space
02679          ! from frequency space
02680          Comptemp2=fft(Gn,inv=.true.)
02681          !
02682          ! Determine mass flux as function of time and let the flux gradually
02683          ! increase and decrease in and out the wave time record using the earlier
02684          ! specified window
02685          Comptemp2=Comptemp2/sqrt(dble(wp%tslen))
02686          q(j,:,iq)=dreal(Comptemp2*wp%tslen)*wp%taperf
02687       enddo ! iq=1,3
02688    enddo ! j=1,s%ny+1
02689    !
02690    ! free memory
02691    deallocate(Comptemp,Comptemp2,Ftemp)
02692    !
02693    if (.not. waveBoundaryParameters%nonhspectrum) then
02694       if(allocated(waveBoundaryTimeSeries%qxbct)) deallocate(waveBoundaryTimeSeries%qxbct)
02695       if(allocated(waveBoundaryTimeSeries%qybct)) deallocate(waveBoundaryTimeSeries%qybct)
02696       allocate(waveBoundaryTimeSeries%qxbct(npb,tslenbc+2))
02697       allocate(waveBoundaryTimeSeries%qxbct(npb,tslenbc+2))
02698       if (wp%dtchanged) then
02699          ! Interpolate from internal time axis to output time axis
02700          do it=2,wp%tslenbc+1
02701             do j=1,npb
02702                call linear_interp(wp%tin,q(j,:,1),wp%tslen, &
02703                (it-1)*wp%dtbc,waveBoundaryTimeSeries%qxbct(j,it),status)
02704                call linear_interp(wp%tin,q(j,:,2),wp%tslen, &
02705                (it-1)*wp%dtbc,waveBoundaryTimeSeries%qybct(j,it),status)
02706             enddo
02707          enddo
02708       else
02709          ! no need for interpolation
02710          waveBoundaryTimeSeries%qxbct(:,2:wp%tslenbc+1) = q(:,:,1)
02711          waveBoundaryTimeSeries%qybct(:,2:wp%tslenbc+1) = q(:,:,2)
02712       endif
02713       waveBoundaryTimeSeries%qxbct(:,1) = waveBoundaryTimeSeries%qxbct(:,2)
02714       waveBoundaryTimeSeries%qxbct(:,wp%tslenbc+2) = waveBoundaryTimeSeries%qxbct(:,wp%tslenbc+1)
02715       waveBoundaryTimeSeries%qybct(:,1) = waveBoundaryTimeSeries%qybct(:,2)
02716       waveBoundaryTimeSeries%qybct(:,wp%tslenbc+2) = waveBoundaryTimeSeries%qybct(:,wp%tslenbc+1)
02717    else
02718       do j=1,npb
02719          ! add to velocity time series
02720          wp%uits(j,:)=wp%uits(j,:)+q(j,:,1)/hb0
02721          ! add to surface elevation time series
02722          wp%zsits(j,:)=wp%zsits(j,:)+q(j,:,3)
02723       enddo
02724    endif ! par%nonhspectrum==1
02725 
02726    ! Free memory
02727    deallocate(Eforc,D,deltheta,KKx,KKy,dphi3,k3,cg3,theta3,Gn,Abnd,q)
02728 
02729 end subroutine generate_qbcf
02730 
02731 
02732 ! --------------------------------------------------------------
02733 ! --------------- Non-hydrostatic wave time --------------------
02734 ! ---------------- series file generation ----------------------
02735 subroutine generate_nhtimeseries_file(wp)
02736 
02737 #ifdef BUILDXBEACH
02738    use logging_module
02739 #endif
02740    use wave_boundary_datastore
02741 
02742    implicit none
02743 
02744    ! input/output
02745    type(waveparamsnew),intent(inout)            :: wp
02746    ! internal
02747 
02748 #ifdef BUILDXBEACH
02749    call writelog('ls','','Writing short wave time series to ',wp%nhfilename)
02750 #endif
02751    if(allocated(waveBoundaryTimeSeries%zsbct)) deallocate(waveBoundaryTimeSeries%zsbct)
02752    if(allocated(waveBoundaryTimeSeries%ubct)) deallocate(waveBoundaryTimeSeries%ubct)
02753    allocate(waveBoundaryTimeSeries%zsbct(npb,wp%tslen+2))
02754    allocate(waveBoundaryTimeSeries%ubct(npb,wp%tslen+2))
02755 
02756    waveBoundaryTimeSeries%zsbct(:,2:wp%tslen+1) = wp%zsits
02757    waveBoundaryTimeSeries%ubct(:,2:wp%tslen+1) = wp%uits
02758 
02759    waveBoundaryTimeSeries%zsbct(:,1) = waveBoundaryTimeSeries%zsbct(:,2)
02760    waveBoundaryTimeSeries%zsbct(:,wp%tslen+2) = waveBoundaryTimeSeries%zsbct(:,wp%tslen+1)
02761    waveBoundaryTimeSeries%ubct(:,1) = waveBoundaryTimeSeries%ubct(:,2)
02762    waveBoundaryTimeSeries%ubct(:,wp%tslen+2) = waveBoundaryTimeSeries%ubct(:,wp%tslen+1)
02763 
02764 end subroutine generate_nhtimeseries_file
02765 
02766 
02767 
02768 end module
 All Classes Files Functions Variables Defines