WAVEWATCH III  beta 0.0.1
w3gkemd Module Reference

Functions/Subroutines

subroutine, public prepkernelio (nk, nth, sig, th, act)
 
subroutine, public calcqrsnl (nk, nth, sig, th, t0, t1, Cvk0, Cvk1, Inpqr0, Snl, Dnl, Kurt)
 

Variables

real, public qr_depth
 
real, public qr_oml
 
integer, public qi_disc
 
integer, public qi_kev
 
integer, public qi_interp
 
integer(kind=8), public qi_nnz
 

Function/Subroutine Documentation

◆ calcqrsnl()

subroutine, public w3gkemd::calcqrsnl ( integer, intent(in)  nk,
integer, intent(in)  nth,
real, dimension(nk), intent(in)  sig,
real, dimension(nth), intent(in)  th,
real, intent(inout)  t0,
real, intent(in)  t1,
real, dimension(nk*nth), intent(inout)  Cvk0,
real, dimension(nk*nth), intent(in)  Cvk1,
complex, dimension(:), intent(inout)  Inpqr0,
real, dimension(nk*nth), intent(out)  Snl,
real, dimension(nk*nth), intent(out)  Dnl,
real, intent(out)  Kurt 
)

Definition at line 1625 of file w3gkemd.F90.

1625  !/
1626  !/ 09-Dec-2018 : Origination ( Q. Liu )
1627  !/ 09-Dec-2018 : Extracted from Odin's subr. `calcQRSNL`
1628  !/ ( Q. Liu )
1629  !/ 10-Jun-2019 : Include Janssen's KE properly ( Q. Liu )
1630  !/ 07-Jun-2021 : Switch off the cal. of kurtosis (!|KT|)
1631  !/ ( Q. Liu )
1632  !/
1633  ! 1. Purpose:
1634  ! Calculate the nonlinear transfer rates for a given frequency
1635  ! grid and given action density spectrum C(\vec{k}).
1636  !
1637  ! According to J09 and GS13, C(\vec{k}) is given by
1638  ! /
1639  ! m0 = | F(\vec{k}) d \vec{k}
1640  ! /
1641  !
1642  ! F(\vec{k}) = ω C(\vec{k}) / g,
1643  !
1644  ! whereas the wave action density spectrum used in WW3 is given by
1645  ! F(\vec{k}) d \vec{k} = F(k, θ) dk dθ
1646  ! = N(k, θ) ω dk dθ
1647  !
1648  ! Thus, we have
1649  ! C(\vec{k}) = N * g / k.
1650  !
1651  ! 2. Method
1652  ! See GS13 & GB16 for all the details.
1653  !
1654  ! ◆ t0, t1 here are time `relative` to the begining time of the
1655  ! simulaiton, rather than the `absolute` time
1656  !
1657  ! ◆ Cvk0, Cvk1, Snl, Dnl shoud be organized/stored in the same way as
1658  ! qr_kx, qr_ky, qr_dk, qr_om
1659  !/
1660  implicit none
1661  !
1662  integer, intent(in) :: nk ! # of frequencies
1663  integer, intent(in) :: nth ! # of directions
1664  real, intent(in) :: sig(nk) ! radian frequency (rad)
1665  real, intent(in) :: th(nth) ! θ (rad) [equally spaced,
1666  ! but may start from non-zero
1667  !
1668  real, intent(inout) :: t0 ! previous time step
1669  real, intent(inout) :: Cvk0(nk*nth) ! Action density @ t0
1670  complex, intent(inout) :: Inpqr0(:) ! I(t) @ t0
1671  !
1672  real, intent(in) :: t1 ! current time step
1673  real, intent(in) :: Cvk1(nk*nth) ! Action density @ t1
1674  ! ... C(\vec{k})
1675  !
1676  real, intent(out) :: Snl(nk*nth) ! Snl = dC/dt
1677  real, intent(out) :: Dnl(nk*nth) ! Dnl
1678  real, intent(out) :: Kurt ! Kurtosis
1679  !
1680  ! Local parameters
1681  !
1682  real :: DelT ! Δt
1683  logical, save :: FlRead = .true.
1684  integer :: num_I, ns
1685  real :: Dvk0(nk*nth),& ! Odin's discrete Cvk @ t0
1686  Dvk1(nk*nth) ! ... @ t1
1687  real, allocatable, save :: Cvk0_R(:), & ! C₄ @ t0
1688  Cvk1_R(:) ! @ t1
1689  real, allocatable, save :: Fnpqr0(:), & ! C prod. @ t0
1690  Fnpqr1(:), & ! C prod. @ t1
1691  Mnpqr (:) ! δC_1/δt * δk_1
1692  complex, allocatable, save :: Inpqr1(:), & ! I(t) @ t1
1693  ETau(:), & ! exp(iΔωt)
1694  EDelT(:) ! exp(iΔωΔt)
1695  !
1696  real, allocatable, save :: Mnp1D(:), Mnp2D(:, :)
1697  real :: SecM2 ! Second-order moment²
1698  !/
1699  !
1700  ! Initilization
1701  ns = nk * nth
1702  qi_nrsm = ns * ns
1703  !
1704  ! Only constant depth is allowed now. Accordingly, we only need a single
1705  ! binary config file which provides the wavenumber grid and kernel
1706  ! coefficients.
1707  !
1708  ! Read quartets & kernel coefficients in
1709  if (flread) then
1710  ! Only read data once
1711  call prepkernelio(nk, nth, sig, th, 'READ')
1712  flread = .false.
1713  ! write(*, *) "⊚ → [R] FLag for Reading Kernels becomes |", FlRead, "|"
1714  ! Allocate arrays
1715  ! ✓ A variable with the SAVE attribute retains its value and definition,
1716  ! association, and `allocation` status on exit from a procedure
1717  !
1718  if (allocated(fnpqr0)) deallocate(fnpqr0); allocate(fnpqr0(qi_nnz))
1719  if (allocated(fnpqr1)) deallocate(fnpqr1); allocate(fnpqr1(qi_nnz))
1720  if (allocated(etau )) deallocate(etau ); allocate(etau(qi_nnz))
1721  if (allocated(edelt )) deallocate(edelt ); allocate(edelt(qi_nnz))
1722  if (allocated(mnpqr )) deallocate(mnpqr ); allocate(mnpqr(qi_nnz))
1723  if (allocated(inpqr1)) deallocate(inpqr1); allocate(inpqr1(qi_nnz))
1724  !
1725  if (allocated(mnp1d)) deallocate(mnp1d); allocate(mnp1d(qi_nrsm))
1726  if (allocated(mnp2d)) deallocate(mnp2d); allocate(mnp2d(ns, ns))
1727  !
1728  if (qi_disc .eq. 0) then
1729  if (allocated(cvk0_r)) deallocate(cvk0_r); allocate(cvk0_r(qi_nnz))
1730  if (allocated(cvk1_r)) deallocate(cvk1_r); allocate(cvk1_r(qi_nnz))
1731  end if
1732  !
1733  end if
1734  !
1735  ! Screen output (check whether the kernel data are stored in memory)
1736 #ifdef W3_TS
1737  write(*, *) "◆ qr_depth :", qr_depth
1738  write(*, *) "◆ qr_oml :", qr_oml
1739  write(*, *) "◆ qi_disc :", qi_disc
1740  write(*, *) "◆ qi_kev :", qi_kev
1741  write(*, *) "◆ qi_nnz :", qi_nnz
1742  write(*, *) "◆ qi_NN(:10) :", qi_nn(:10)
1743  write(*, *) "◆ qr_TKern(:10) :", qr_tkern(:10)
1744  write(*, *) "◆ qr_TKurt(:10) :", qr_tkurt(:10)
1745  write(*, *) "◆ qr_sumQR(:10) :", qr_sumqr(:10)
1746 #endif
1747  !
1748  num_i = size(inpqr0)
1749  if (num_i .ne. qi_nnz) then
1750  write(*, 1001) 'CalcQRSNL'
1751  call exit(1)
1752  end if
1753  !
1754  ! Start to calc. Snl term
1755  if (qi_disc == 0) then
1756  ! Define ΔC = dC/dt * Δk Δt, we have ΔC₁ = ΔC₂ = -ΔC₃ = -ΔC₄ (Δt can be
1757  ! removed by taking the unit time)
1758  !
1759  ! Cvk0/1_R (bilinear interp. or nearest bin)
1760  if (qi_interp .eq. 0) then
1761  cvk0_r = cvk0(qi_rr)
1762  cvk1_r = cvk1(qi_rr)
1763  !
1764  else if (qi_interp .eq. 1) then
1765  cvk0_r = qr_bwgh(1, :) * cvk0(qi_bind(1, :)) + &
1766  qr_bwgh(2, :) * cvk0(qi_bind(2, :)) + &
1767  qr_bwgh(3, :) * cvk0(qi_bind(3, :)) + &
1768  qr_bwgh(4, :) * cvk0(qi_bind(4, :))
1769  !
1770  cvk1_r = qr_bwgh(1, :) * cvk1(qi_bind(1, :)) + &
1771  qr_bwgh(2, :) * cvk1(qi_bind(2, :)) + &
1772  qr_bwgh(3, :) * cvk1(qi_bind(3, :)) + &
1773  qr_bwgh(4, :) * cvk1(qi_bind(4, :))
1774  !
1775  if (qi_bound .eq. 1) then
1776  cvk0_r = cvk0_r * qr_bdry
1777  cvk1_r = cvk1_r * qr_bdry
1778  end if
1779  !
1780  end if
1781  !
1782  ! F = [C₃ C₄ (C₁ + C₂) - C₁ C₂ (C₃ + C₄)] dk₂ dk₃ dk₄ ∙ dk₁
1783  ! dk₄ vanishes with the δ function
1784  fnpqr0 = (cvk0(qi_qq) * cvk0_r * ( &
1785  cvk0(qi_nn) + cvk0(qi_pp) ) - &
1786  cvk0(qi_nn) * cvk0(qi_pp) * ( &
1787  cvk0(qi_qq) + cvk0_r )) * &
1788  qr_dk(qi_nn) * qr_dk(qi_pp) * qr_dk(qi_qq)
1789  !
1790  fnpqr1 = (cvk1(qi_qq) * cvk1_r * ( &
1791  cvk1(qi_nn) + cvk1(qi_pp) ) - &
1792  cvk1(qi_nn) * cvk1(qi_pp) * ( &
1793  cvk1(qi_qq) + cvk1_r )) * &
1794  qr_dk(qi_nn) * qr_dk(qi_pp) * qr_dk(qi_qq)
1795  !
1796  else if (qi_disc == 1) then
1797  ! Used in GS13 & GB16
1798  ! F = [C₃dk₃ C₄dk₄ (C₁dk₁ + C₂dk₂) - C₁dk₁ C₂dk₂ (C₃dk₃ + C₄dk₄)]
1799  ! It seems the bilinear interpolation for this discretization approach
1800  ! is not very meaningful.
1801  dvk0 = cvk0 * qr_dk
1802  fnpqr0 = dvk0(qi_qq) * dvk0(qi_rr) * ( &
1803  dvk0(qi_nn) + dvk0(qi_pp) ) - &
1804  dvk0(qi_nn) * dvk0(qi_pp) * ( &
1805  dvk0(qi_qq) + dvk0(qi_rr) )
1806  !
1807  dvk1 = cvk1 * qr_dk
1808  fnpqr1 = dvk1(qi_qq) * dvk1(qi_rr) * ( &
1809  dvk1(qi_nn) + dvk1(qi_pp) ) - &
1810  dvk1(qi_nn) * dvk1(qi_pp) * ( &
1811  dvk1(qi_qq) + dvk1(qi_rr) )
1812  !
1813  end if
1814  !|KT|! Calc m2 for Kurtosis estimation ((2.6) of Annekov & Shrira (2013))
1815  !|KT| SecM2 = sum(Cvk1 * qr_om * qr_dk) ** 2.
1816  !
1817  ! write(*, *) '.... Input args: t0, t1 :', t0, t1
1818  if (abs(t1) < qr_eps) then
1819  ! t1 = 0.0 [essentially I₁ = 0 → I₀ = 0]
1820  t0 = 0.0
1821  cvk0 = cvk1
1822  inpqr0 = (0.0, 0.0) ! \int_{0}^{0} dt = 0
1823  snl = 0.0
1824  dnl = 0.0
1825  kurt = 0.0
1826  else
1827  ! t1 ≠ 0.0
1828  delt = t1 - t0
1829  if (delt < 0.0) then
1830  write(*, 1002) 'CalcQRSNL'
1831  call exit(2)
1832  end if
1833  etau = exp(qc_iu * cmplx(qr_dom * t1)) ! exp(iΔωt)
1834  edelt = exp(qc_iu * cmplx(qr_dom * delt)) ! exp(iΔωΔt)
1835  !
1836  ! ◆ Calc. I₁: note here I₁ = I(t₁) dk₁ dk₂ dk₃ for both qi_disc = 0/1
1837  if (qi_kev .eq. 0) then
1838  ! GKE from GS13, GB16
1839  inpqr1 = inpqr0 + cmplx(0.5 * delt) * &
1840  conjg(etau) * & ! exp(-iΔωt)
1841  (cmplx(fnpqr0) * edelt + cmplx(fnpqr1))
1842  else if (qi_kev .eq. 1) then
1843  ! KE from J03 (Fnpqr1 is taken outside the time integral; Fnpqr0 is not
1844  ! used in this case; and the real part of Inpqr1 is sin(Δωt)/Δω, and
1845  ! the imaginary part is [1 - cos(Δωt)] / Δω
1846  ! Approximation used before
1847  ! Inpqr1 = Inpqr0 + cmplx(0.5 * DelT) * &
1848  ! conjg(ETau) * (EDelT + 1)
1849  !
1850  where (abs(qr_dom) < qr_eps)
1851  ! Δω = 0., sin(Δωt)/Δω ~ t, [1 - cos(Δωt)] / Δω ~ 0
1852  inpqr1 = cmplx(t1, 0.)
1853  elsewhere
1854  ! Δω ≠ 0., cacl. sin(Δωt)/Δω & [1 - cos(Δωt)] / Δω directly
1855  ! TODO: the sign of cos is not clear yet.
1856  inpqr1 = cmplx(sin(qr_dom * t1) / qr_dom, &
1857  (1 - cos(qr_dom * t1)) / qr_dom)
1858  end where
1859  end if
1860  ! ◆ Snl [Tranfer Integal]
1861  if (qi_kev .eq. 0) then
1862  ! GKE from GS13, GB16
1863  mnpqr = 4.0 * (qr_tkern ** 2.) * real(etau * inpqr1)
1864  else if (qi_kev .eq. 1) then
1865  ! KE from J03
1866  ! Mnpqr = 4.0 * (qr_TKern ** 2.) * Fnpqr1 * real(ETau * Inpqr1)
1867  mnpqr = 4.0 * (qr_tkern ** 2.) * fnpqr1 * real(inpqr1)
1868  end if
1869  ! Calc. Σ over Q, R [Mnpqr is a upper triangular sparse matrix]
1870  ! dN₁/dt = - dN₃/dt → anti-symmetric array operation
1871  ! Mnp1D = (Mnpqr - Mnpqr^{T}) × S_{qr}
1872  call asymsmattimvec(qi_nrsm, mnpqr, qi_iccos, qi_ircsr, qr_sumqr, mnp1d, -1.0)
1873  ! Calc. Σ over P [Mnp2D is a upper triangular matrix]
1874  ! dN₁/dt = dN₂/dt → symmetric array operation
1875  ! Snl = {Σ (Mnp + Mnp^{T}) ⊙ S_{p}} / d\vec{k₁}
1876  mnp2d = reshape(mnp1d, (/ns, ns/))
1877  snl = sum((mnp2d + transpose(mnp2d)) * qr_sumnp, 2) / qr_dk
1878  ! ◆ Conservation Check
1879 #ifdef W3_TS
1880  write(*, '(A, E15.3)') ' ← {WW3 GKE } ΣSnl(k) * dk: ', sum(snl * qr_dk)
1881 #endif
1882  !
1883  ! ◆ Dnl [Diagonal term] <TODO>
1884  ! i) it is easy to calculate Dnl for Janssen's KE (but we may
1885  ! have to abandon the sparse array approach)
1886  ! ii) it is challenging to get Dnl for GKE.
1887  dnl = 0.0
1888  kurt = 0.0
1889  !
1890  !|KT|! ◆ Kurtosis
1891  !|KT| if (qi_kev .eq. 0) then
1892  !|KT|! GKE from GS13, GB16
1893  !|KT| Mnpqr = -3.0 / SecM2 * qr_TKurt * aimag(ETau * Inpqr1)
1894  !|KT| else if (qi_kev .eq. 1) then
1895  !|KT|! KE from J03 (here the imaginary part becomes [1 - cos(Δωt)] / Δω
1896  !|KT|! Mnpqr = -3.0 / SecM2 * qr_TKurt * Fnpqr1 * aimag(ETau * Inpqr1)
1897  !|KT| Mnpqr = -3.0 / SecM2 * qr_TKurt * Fnpqr1 * aimag(Inpqr1)
1898  !|KT| end if
1899  !|KT|! Calc. Σ over Q, R [Mnpqr is a upper triangular sparse matrix]
1900  !|KT|! symmetric array operation Mnp1D = (Mnpqr - Mnpqr^{T}) × S_{qr}
1901  !|KT| call ASymSmatTimVec(qi_nrsm, Mnpqr, qi_icCos, qi_irCsr, qr_sumQR, Mnp1D, 1.0)
1902  !|KT| Mnp2D = reshape(Mnp1D, (/ns, ns/))
1903  !|KT| Kurt = sum((Mnp2D + transpose(Mnp2D)) * qr_sumNP)
1904  !
1905  ! I₁ → I₀ for next computation (time step)
1906  t0 = t1
1907  cvk0 = cvk1
1908  inpqr0 = inpqr1
1909  end if
1910  !
1911  ! write(*, *) '.... Output args: t0, t1 :', t0, t1
1912  !
1913  ! Formats
1914 1001 FORMAT(/' *** GKE ERROR IN gkeModule : '/ &
1915  ' Subr. ', a, ': the stored total number of quartets &
1916  & and the size of Inpqr0 do not match !'/)
1917 1002 FORMAT(/' *** GKE ERROR IN gkeModule : '/ &
1918  ' Subr. ', a, ': t0 ≤ t1 is not satisfied !'/)
1919  !/

References prepkernelio(), qi_disc, qi_interp, qi_kev, qi_nnz, qr_depth, and qr_oml.

Referenced by w3snl5md::w3snl5().

◆ prepkernelio()

subroutine, public w3gkemd::prepkernelio ( integer, intent(in)  nk,
integer, intent(in)  nth,
real, dimension(nk), intent(in)  sig,
real, dimension(nth), intent(in)  th,
character(len=*), intent(in)  act 
)

Definition at line 1202 of file w3gkemd.F90.

1202  !/
1203  !/ 04-Dec-2018 : Origination ( Q. Liu )
1204  !/ 04-Dec-2018 : Extracted from Odin's subr. `calcQRSNL`
1205  !/ ( Q. Liu )
1206  !/
1207  ! 1. Purpose:
1208  ! Read & Write the pre-computed kernel coefficients `T` for a given
1209  ! discrete wavenumber grid and water depth.
1210  !
1211  ! For a typical 2D finite-depth wave model application, the wavenumber
1212  ! grid varies according to water depth. Consequently, the quartet
1213  ! configuration and interactive kernel coefficients will change as
1214  ! well.
1215  !
1216  ! Therefore, it seems extremely difficult to handle a 2D varied-depth
1217  ! application as the total number of quartets (qi_nnz) and thus the
1218  ! array size of `Inpqr0` vary [see CalcQRSNL]. Initializing a 2D
1219  ! array `Inpqr0` with a fixed size of (qi_nnz, nsea) becomes impossible.
1220  !
1221  ! So currently we are limiting ourself to deep-water or constant
1222  ! finite-deep cases.
1223  !
1224  !/
1225  USE constants, ONLY: file_endian
1226 
1227  implicit none
1228  !
1229  integer, intent(in) :: nk ! # of frequencies
1230  integer, intent(in) :: nth ! # of directions
1231  real, intent(in) :: sig(nk) ! radian frequency (rad)
1232  real, intent(in) :: th(nth) ! θ (rad) [equally spaced,
1233  ! but may start from non-zero
1234  ! value]
1235  character(len=*), intent(in) :: act ! 'read' or 'write'
1236  !
1237  ! Local parameters
1238  integer :: ns, iq, i1, i3, icol
1239  integer(kind=8) :: rpos ! reading position
1240  integer, allocatable :: irow_coo(:), & ! row of coo mat
1241  icooTcsr(:) ! index for coo → csr
1242  !/
1243  ! Initilization
1244  ns = nk * nth
1245  qi_nrsm = ns * ns
1246  ! → Be very careful that the size of `qi_irCsr` is not qi_nnz !
1247  if (allocated(qi_ircsr)) deallocate(qi_ircsr); allocate(qi_ircsr(qi_nrsm+1))
1248  if (allocated(qr_sumqr)) deallocate(qr_sumqr); allocate(qr_sumqr(qi_nrsm))
1249  if (allocated(qr_sumnp)) deallocate(qr_sumnp); allocate(qr_sumnp(ns, ns))
1250  ! qr_dk/om
1251  if (allocated(qr_dk)) deallocate(qr_dk); allocate(qr_dk(ns))
1252  if (allocated(qr_om)) deallocate(qr_om); allocate(qr_om(ns))
1253  !
1254  ! Determine water depth for the whole module, which will be used by
1255  ! `T` & `Q` func.
1256  qr_depth = max(0., min(qr_depth, qr_dmax))
1257  qi_disc = max(0, min(qi_disc, 1))
1258  qi_kev = max(0, min(qi_kev, 1))
1259  qi_interp = max(0, min(qi_interp, 1))
1260  if (qi_disc .eq. 1) qi_interp = 0
1261  !
1262  ! Determine the name for the binary file which stores the quartet
1263  ! configuration and the corresponding kernel coefficient ['gkev?_d????.cfg]
1264  ! constant-depth or deep water
1265  write(qs_cfg, "(A, '_d', I4.4, '.cfg')") trim(qs_ver), int(qr_depth)
1266  !
1267  if (trim(act) == 'WRITE') then
1268  ! Calc KGrid → [qr_kx/ky/dk/om/wn]
1269  if (allocated(qr_kx)) deallocate(qr_kx); allocate(qr_kx(ns))
1270  if (allocated(qr_ky)) deallocate(qr_ky); allocate(qr_ky(ns))
1271  if (allocated(qr_wn1)) deallocate(qr_wn1); allocate(qr_wn1(nk))
1272  call prepkgrid(nk, nth, qr_depth, sig, th)
1273  ! Find total # of quartets → [qi_nnz]
1274  call findquartetnumber(ns, qr_kx, qr_ky, qr_om, qr_oml, qi_nnz)
1275  ! Find Quartet Config. → [qi_NN/PP/QQ/RR & qr_k4x/k4y/om4]
1276  if (allocated(qi_nn)) deallocate(qi_nn); allocate(qi_nn(qi_nnz))
1277  if (allocated(qi_pp)) deallocate(qi_pp); allocate(qi_pp(qi_nnz))
1278  if (allocated(qi_qq)) deallocate(qi_qq); allocate(qi_qq(qi_nnz))
1279  if (allocated(qi_rr)) deallocate(qi_rr); allocate(qi_rr(qi_nnz))
1280  !
1281  if (allocated(qr_k4x)) deallocate(qr_k4x); allocate(qr_k4x(qi_nnz))
1282  if (allocated(qr_k4y)) deallocate(qr_k4y); allocate(qr_k4y(qi_nnz))
1283  if (allocated(qr_om4)) deallocate(qr_om4); allocate(qr_om4(qi_nnz))
1284  !
1285  call findquartetconfig(ns, qr_kx, qr_ky, qr_om, qr_oml, qi_nnz, &
1286  qi_nn, qi_pp, qi_qq, qi_rr, &
1287  qr_k4x, qr_k4y, qr_om4)
1288  !
1289  ! Calc Kernel `T`
1290  if (allocated(qr_tkern)) deallocate(qr_tkern); allocate(qr_tkern(qi_nnz))
1291  if (allocated(qr_tkurt)) deallocate(qr_tkurt); allocate(qr_tkurt(qi_nnz))
1292  if (allocated(qr_dom)) deallocate(qr_dom); allocate(qr_dom(qi_nnz))
1293  !
1294  do iq = 1, qi_nnz
1295  qr_tkern(iq) = tfunc(qr_kx(qi_nn(iq)), qr_ky(qi_nn(iq)),&
1296  qr_kx(qi_pp(iq)), qr_ky(qi_pp(iq)),&
1297  qr_kx(qi_qq(iq)), qr_ky(qi_qq(iq)),&
1298  qr_k4x(iq) , qr_k4y(iq) )
1299  end do
1300  ! Calc Kernel coeff. for Kurtosis
1301  qr_tkurt = qr_tkern * sqrt(qr_om(qi_nn) * qr_om(qi_pp) * qr_om(qi_qq) * qr_om4)
1302  ! Calc Δω (Remove very small Δω; Δω=0 → resonant quartets)
1303  qr_dom = qr_om(qi_nn) + qr_om(qi_pp) - qr_om(qi_qq) - qr_om4
1304  ! TODO: should we use double precision for qr_dom
1305  ! Note for GNU compiler, qr_eps~1.2E-7 (single prec.) & ~2.2E-16 (double).
1306  ! The values above are also true for the intel compiler.
1307  ! sin(Δωt) / Δω is very different for Δω = 0 and Δw~1E-7 when t is large.
1308  where(abs(qr_dom) < qr_eps) qr_dom = 0.0
1309  !
1310  ! Calc interp. weight if necessary
1311  if (qi_interp .eq. 1) then
1312  if (allocated(qi_bind)) deallocate(qi_bind); allocate(qi_bind(4, qi_nnz))
1313  if (allocated(qr_bwgh)) deallocate(qr_bwgh); allocate(qr_bwgh(4, qi_nnz))
1314  if (qi_bound .eq. 1 ) then
1315  if (allocated(qr_bdry)) deallocate(qr_bdry); allocate(qr_bdry(qi_nnz))
1316  end if
1317  call biinterpwt(nk, nth, qr_wn1, th)
1318  end if
1319  !
1320  deallocate(qr_kx, qr_ky)
1321  deallocate(qr_k4x, qr_k4y, qr_om4)
1322  if (qi_interp .eq. 1) deallocate(qr_wn1)
1323  !
1324  ! Sparse matrix index conversion [icCos shared by two formats: COO & CSR]
1325  if (allocated(qi_iccos)) deallocate(qi_iccos); allocate(qi_iccos(qi_nnz))
1326  if (allocated(irow_coo)) deallocate(irow_coo); allocate(irow_coo(qi_nnz))
1327  if (allocated(icootcsr)) deallocate(icootcsr); allocate(icootcsr(qi_nnz))
1328  !
1329  irow_coo = qi_nn + (qi_pp - 1) * ns
1330  qi_iccos = qi_qq + (qi_rr - 1) * ns
1331  !
1332  ! FindQuartetConfig stores the quartet row by row in a discontinuous order,
1333  ! so we need keep icooTcsr & qi_irCsr
1334  call coocsrind(qi_nrsm, qi_nnz, irow_coo, qi_iccos, icootcsr, qi_ircsr)
1335  !
1336  ! Reorder index & arrays [coo → crs]
1337  qi_nn = qi_nn(icootcsr) ! used for calc. action prod.
1338  qi_pp = qi_pp(icootcsr)
1339  qi_qq = qi_qq(icootcsr)
1340  qi_rr = qi_rr(icootcsr)
1341  qr_tkern = qr_tkern(icootcsr)
1342  qr_tkurt = qr_tkurt(icootcsr)
1343  qr_dom = qr_dom(icootcsr) ! Δω
1344  !
1345  if (qi_interp .eq. 1) then ! bilinear interp. weight
1346  qi_bind = qi_bind(:, icootcsr)
1347  qr_bwgh = qr_bwgh(:, icootcsr)
1348  if (qi_bound .eq. 1) qr_bdry = qr_bdry(icootcsr)
1349  end if
1350  !
1351  qi_iccos = qi_iccos(icootcsr)
1352  deallocate(irow_coo, icootcsr)
1353  !
1354  ! Construct the sum vectors [used for 6D integration]
1355  ! Σ over Q, R [qr_sumQR]
1356  qr_sumqr = 2.0
1357  do i3 = 1, ns
1358  ! i3 == i4
1359  icol = i3 + (i3 - 1) * ns
1360  qr_sumqr(icol) = 1.0
1361  end do
1362  ! Σ over P [qr_sumNP]
1363  qr_sumnp = 1.0
1364  do i1 = 1, ns
1365  ! i1 == i2
1366  qr_sumnp(i1, i1) = 0.5
1367  end do
1368  !
1369  ! WRITE KGrid & Kernel into qs_cfg
1370  write(*, *) '[W] Writing |', trim(qs_cfg), '| ...'
1371  open(51, file=trim(qs_cfg), form='unformatted', convert=file_endian, &
1372  access='stream', status='replace')
1373  !
1374  ! It is not necessary to store `ns` since `ns = nk * nth`
1375  write(51) nk, nth, sig, th ! (f, θ) grid
1376  write(51) qr_depth, qr_oml, qi_disc, &
1377  qi_kev, qi_interp ! parameters
1378  write(51) qr_om, qr_dk
1379  write(51) qi_nnz
1380  write(51) qi_nn, qi_pp, qi_qq, qi_rr
1381  write(51) qr_tkern, qr_tkurt, qr_dom
1382  write(51) qi_iccos, qi_ircsr
1383  write(51) qr_sumqr, qr_sumnp
1384  !
1385  if (qi_interp .eq. 1) write(51) qi_bind, qr_bwgh
1386  if ( (qi_interp .eq. 1) .and. (qi_bound .eq. 1) ) &
1387  write(51) qr_bdry
1388  close(51)
1389  ! Screen Test
1390 #ifdef W3_TS
1391  write(*, *) "[W] qr_depth: ", qr_depth
1392  write(*, *) "[W] qr_oml : ", qr_oml
1393  write(*, *) "[W] qi_disc : ", qi_disc
1394  write(*, *) "[W] qi_kev : ", qi_kev
1395  write(*, *) "[W] qr_om : ", qr_om
1396  write(*, *) "[W] qr_dk : ", qr_dk
1397  write(*, *) "[W] The total number of quartets is ", qi_nnz
1398  write(*, *) '[W] qi_NN : ', qi_nn
1399  write(*, *) '[W] qi_PP : ', qi_pp
1400  write(*, *) '[W] qi_QQ : ', qi_qq
1401  write(*, *) '[W] qi_RR : ', qi_rr
1402  write(*, *) '[W] qr_TKern: ', qr_tkern
1403  write(*, *) '[W] qr_TKurt: ', qr_tkurt
1404  write(*, *) '[W] qr_dom : ', qr_dom
1405  write(*, *) '[W] qi_icCos: ', qi_iccos
1406  write(*, *) '[W] qi_irCsr: ', qi_ircsr
1407  write(*, *) '[W] Σ_QR : ', qr_sumqr(1: qi_nrsm: ns+1)
1408  write(*, *) '[W] Σ_P : ', (qr_sumnp(iq, iq), iq = 1, ns)
1409 #endif
1410  !
1411  else if (trim(act) == 'READ') then
1412  write(*, *) '⊚ → [R] Reading |', trim(qs_cfg), '| ...'
1413  open(51, file=trim(qs_cfg), form='unformatted', convert=file_endian, &
1414  access='stream', status='old')
1415  ! nk, nth, sig, th can be skipped by using pos
1416  rpos = 1_8 + qi_lrb * (2_8 + nk + nth)
1417  read(51, pos=rpos) qr_depth, qr_oml, qi_disc, &
1418  qi_kev, qi_interp
1419  !
1420  ! read ω & Δ\vec{k}
1421  read(51) qr_om, qr_dk
1422  ! read total # of quartets
1423  read(51) qi_nnz
1424  write(*, *) "⊚ → [R] The total number of quartets is ", qi_nnz
1425  write(*, *)
1426  ! allocate arrays
1427  if (allocated(qi_nn)) deallocate(qi_nn); allocate(qi_nn(qi_nnz))
1428  if (allocated(qi_pp)) deallocate(qi_pp); allocate(qi_pp(qi_nnz))
1429  if (allocated(qi_qq)) deallocate(qi_qq); allocate(qi_qq(qi_nnz))
1430  if (allocated(qi_rr)) deallocate(qi_rr); allocate(qi_rr(qi_nnz))
1431  !
1432  if (allocated(qr_tkern)) deallocate(qr_tkern); allocate(qr_tkern(qi_nnz))
1433  if (allocated(qr_tkurt)) deallocate(qr_tkurt); allocate(qr_tkurt(qi_nnz))
1434  if (allocated(qr_dom)) deallocate(qr_dom); allocate(qr_dom(qi_nnz))
1435  !
1436  if (allocated(qi_iccos)) deallocate(qi_iccos); allocate(qi_iccos(qi_nnz))
1437  !
1438  read(51) qi_nn, qi_pp, qi_qq, qi_rr
1439  read(51) qr_tkern, qr_tkurt, qr_dom
1440  read(51) qi_iccos, qi_ircsr
1441  read(51) qr_sumqr, qr_sumnp
1442  !
1443  if (qi_interp .eq. 1) then
1444  if (allocated(qi_bind)) deallocate(qi_bind); allocate(qi_bind(4, qi_nnz))
1445  if (allocated(qr_bwgh)) deallocate(qr_bwgh); allocate(qr_bwgh(4, qi_nnz))
1446  read(51) qi_bind, qr_bwgh
1447  !
1448  if (qi_bound .eq. 1) then
1449  if (allocated(qr_bdry)) deallocate(qr_bdry); allocate(qr_bdry(qi_nnz))
1450  read(51) qr_bdry
1451  end if
1452  !
1453  end if
1454  !
1455  close(51)
1456  ! Screen Test
1457 #ifdef W3_TS
1458  write(*, *) "[R] qr_depth: ", qr_depth
1459  write(*, *) "[R] qr_oml : ", qr_oml
1460  write(*, *) "[R] qi_disc : ", qi_disc
1461  write(*, *) "[R] qi_kev : ", qi_kev
1462  write(*, *) "[R] qr_om : ", qr_om
1463  write(*, *) "[R] qr_dk : ", qr_dk
1464  write(*, *) "[R] The total number of quartets is ", qi_nnz
1465  write(*, *) '[R] qi_NN : ', qi_nn
1466  write(*, *) '[R] qi_PP : ', qi_pp
1467  write(*, *) '[R] qi_QQ : ', qi_qq
1468  write(*, *) '[R] qi_RR : ', qi_rr
1469  write(*, *) '[R] qr_TKern: ', qr_tkern
1470  write(*, *) '[R] qr_TKurt: ', qr_tkurt
1471  write(*, *) '[R] qr_dom : ', qr_dom
1472  write(*, *) '[R] qi_icCos: ', qi_iccos
1473  write(*, *) '[R] qi_irCsr: ', qi_ircsr
1474  write(*, *) '[R] Σ_QR : ', qr_sumqr(1: qi_nrsm: ns+1)
1475  write(*, *) '[R] Σ_P : ', (qr_sumnp(iq, iq), iq = 1, ns)
1476 #endif
1477  end if
1478  !/

References file(), constants::file_endian, qi_disc, qi_interp, qi_kev, qi_nnz, qr_depth, and qr_oml.

Referenced by calcqrsnl(), and w3snl5md::insnl5().

Variable Documentation

◆ qi_disc

integer, public w3gkemd::qi_disc

Definition at line 172 of file w3gkemd.F90.

172  integer :: qi_disc ! Discretization of GKE

Referenced by calcqrsnl(), w3snl5md::insnl5(), and prepkernelio().

◆ qi_interp

integer, public w3gkemd::qi_interp

Definition at line 180 of file w3gkemd.F90.

180  integer :: qi_interp ! Interp. option

Referenced by calcqrsnl(), w3snl5md::insnl5(), and prepkernelio().

◆ qi_kev

integer, public w3gkemd::qi_kev

Definition at line 176 of file w3gkemd.F90.

176  integer :: qi_kev ! Version of KE

Referenced by calcqrsnl(), w3snl5md::insnl5(), and prepkernelio().

◆ qi_nnz

integer(kind=8), public w3gkemd::qi_nnz

Definition at line 209 of file w3gkemd.F90.

209  integer(kind=8) :: qi_nnz ! # of quartets

Referenced by calcqrsnl(), w3snl5md::insnl5(), and prepkernelio().

◆ qr_depth

real, public w3gkemd::qr_depth

Definition at line 165 of file w3gkemd.F90.

165  real :: qr_depth ! Real water depth d (m)

Referenced by calcqrsnl(), w3snl5md::insnl5(), prepkernelio(), and w3snl5md::w3snl5().

◆ qr_oml

real, public w3gkemd::qr_oml

Definition at line 167 of file w3gkemd.F90.

167  real :: qr_oml ! λ cut off factor

Referenced by calcqrsnl(), w3snl5md::insnl5(), and prepkernelio().

w3gdatmd::nk
integer, pointer nk
Definition: w3gdatmd.F90:1230
w3gdatmd::sig
real, dimension(:), pointer sig
Definition: w3gdatmd.F90:1234
w3gdatmd::th
real, dimension(:), pointer th
Definition: w3gdatmd.F90:1234
scrip_timers::status
character(len=8), dimension(max_timers), save status
Definition: scrip_timers.f:63
w3gdatmd::nth
integer, pointer nth
Definition: w3gdatmd.F90:1230
file
file(STRINGS ${CMAKE_BINARY_DIR}/switch switch_strings) separate_arguments(switches UNIX_COMMAND $
Definition: CMakeLists.txt:3
constants
Define some much-used constants for global use (all defined as PARAMETER).
Definition: constants.F90:20
constants::file_endian
character(*), parameter file_endian
FILE_ENDIAN Filled by preprocessor with 'big_endian', 'little_endian', or 'native'.
Definition: constants.F90:86