WAVEWATCH III  beta 0.0.1
w3sic5md.F90
Go to the documentation of this file.
1 
9 
10 #include "w3macros.h"
11 !/ ------------------------------------------------------------------- /
25 MODULE w3sic5md
26  !/
27  !/ +-----------------------------------+
28  !/ | WAVEWATCH III NOAA/NCEP |
29  !/ | Q. Liu |
30  !/ | E. Rogers |
31  !/ | FORTRAN 90 |
32  !/ | Last update : 19-May-2021 |
33  !/ +-----------------------------------+
34  !/
35  !/ 15-Mar-2016 : Origination. ( version 5.10 )
36  !/ ( Q. Liu )
37  !/ 15-Mar-2016 : Started from w3sic1/2/3/4 module ( Q. Liu )
38  !/
39  !/ 24-Apr-2017 : Adding more filters ( Q. Liu )
40  !/
41  !/ 29-Apr-2017 : Introducing CMPLX_TANH2 ( Q. Liu )
42  !/
43  !/ 02-Jun-2017 : Update to version 5.16 ( Q. Liu )
44  !/
45  !/ 17-Jun-2017 : Remove some unnecessary lines ( Q. Liu )
46  !/ (cg_ice, detla function, complx_tanh etc.)
47  !/
48  !/ 20-Aug-2018 : Ready to be merged to master (v6.06)( Q. Liu)
49  !/
50  !/ 19-May-2021 : Incl. the RP and M2 model ( Q. Liu)
51  !/
52  !/ 1. Purpose :
53  ! Calculate ice source term S_{ice} according to different ice
54  ! models:
55  ! * 'FS': the viscoelastic, extended Fox and Squire sea ice model
56  ! (Mosig et al. 2015)
57  ! * 'RP': the viscoelastic, Robinson and Palmer model (Mosig et al.
58  ! 2015)
59  ! * 'M2': the order 3 power law model proposed by Meylan et al.
60  ! (2018)
61  !
62  ! Reference:
63  ! Mosig, J.E.M., F. Montiel, and V. A. Squire (2015):
64  ! Comparison of viscoelastic-type models for ocean wave attenuation
65  ! in ice-covered seas, J. Geophys. Res. Oceans, 120, 6072–6090,
66  ! doi:10.1002/2015JC010881.
67  !
68  ! Meylan, M.H., L. Bennetts, J. Mosig, W. Rogers, M. Doble, and
69  ! M. Peter (2018): Dispersion relations, power laws, and energy loss
70  ! for waves in the marginal ice zone. J. Geophys. Res. Oceans, 123,
71  ! 3322–3335, https://doi.org/10.1002/2018JC013776.
72  !
73  ! Liu, Q., W. E. Rogers, A. Babanin, J. Li, and C. Guan (2020):
74  ! Spectral Modeling of Ice-Induced Wave Decay. J. Phys. Oceanogr.,
75  ! 50 (6), 1583–1604.
76  !
77  ! 2. Variables and types :
78  !
79  ! Name Type Scope Description
80  ! ----------------------------------------------------------------
81  ! KSP Int. Private the kind parameter for single precision
82  ! real variables
83  ! KDP Int. Private Same as KSP but for double precision
84  ! KSPC Int. Private the kind parameter for single precision
85  ! complex variables
86  ! KDPC Int. Private Same as KSPC but for double precision
87  ! ERRTOL Real Private A real parameter used for "==" test
88  ! ----------------------------------------------------------------
89  !
90  ! 3. Subroutines and functions :
91  !
92  ! Name Type Scope Description
93  ! ----------------------------------------------------------------
94  ! W3SIC5 Subr. Public Ice source term
95  ! W3IC5WNCG Subr. Public Wavenumber and group velocity of ice-
96  ! coupled waves
97  ! FSDISP Subr. Public Solving the ice-coupled wave dispersion
98  ! BALANCING_MATRIX
99  ! Subr. Private Balancing the matrix before we try to
100  ! find its eigenvalues
101  ! EIG_HQR Subr. Private QR algorithm for real Hessenberg matrix
102  ! (eigenvalues-finding algorithm)
103  ! POLYROOTS Subr. Private Finding roots of a general polynomial
104  ! NR_CORR Func. Private Get the Newton-Raphson correction term
105  ! for iteration
106  ! NR_ROOT Func. Private Newton-Raphson algorithm for solving
107  ! the ice-coupled wave dispersion
108  ! CMPLX_SINH, CMPLX_COSH, CMPLX_TANH2
109  ! Func. Private sinh, cosh, tanh for complex inputs
110  ! INIT_RANDOM_SEED
111  ! Subr. Private Initialize the random seed based on
112  ! the system's time
113  ! ----------------------------------------------------------------
114  !
115  ! 4. Subroutines and functions used :
116  ! See subroutine documentation
117  !
118  ! 5. Remarks :
119  !
120  ! 6. Switches :
121  ! See subroutine documentation
122  !
123  ! 7. Source code:
124  !/
125  !/ ------------------------------------------------------------------- /
126  IMPLICIT NONE
127  !/
128  PUBLIC :: w3sic5, w3ic5wncg, fsdisp
129  PRIVATE :: balancing_matrix, eig_hqr, polyroots
130  PRIVATE :: nr_corr, nr_root
131  PRIVATE :: cmplx_sinh, cmplx_cosh, cmplx_tanh2
132  PRIVATE :: init_random_seed
133  !/
134  PRIVATE :: ksp, kdp, kspc, kdpc, errtol
135  !/ ------------------------------------------------------------------- /
136  !/ Parameter list
137  ! Kind for single- and double-precision real type
138  INTEGER, PARAMETER :: KSP = kind(1.0)
139  INTEGER, PARAMETER :: KDP = kind(1.0d0)
140  !
141  ! Kind for single- and double-precision complex type
142  INTEGER, PARAMETER :: KSPC = kind((1.0, 1.0))
143  INTEGER, PARAMETER :: KDPC = kind((1.0d0, 1.0d0))
144  REAL, PARAMETER :: ERRTOL = 1.e-12
145  !/
146 CONTAINS
147  !/ ------------------------------------------------------------------- /
148  !/
168  SUBROUTINE w3sic5 (A, DEPTH, CG, WN, IX, IY, S, D)
169  !/
170  !/ +-----------------------------------+
171  !/ | WAVEWATCH III NOAA/NCEP |
172  !/ | Q. Liu |
173  !/ | E. Rogers |
174  !/ | FORTRAN 90 |
175  !/ | Last update : 19-May-2021 |
176  !/ +-----------------------------------+
177  !/
178  !/ 23-Mar-2016 : Origination ( version 5.10 )
179  !/ ( Q. Liu)
180  !/ 23-Mar-2016 : Started from w3sic1/2/3/4 subr. ( Q. Liu)
181  !/ 05-Apr-2016 : Options for Cg_{ice} or Cg ( Q. Liu)
182  !/ 25-Apr-2017 : Add more filters ( Q. Liu)
183  !/ 20-Aug-2018 : Ready to be merged to master (v6.06)( Q. Liu)
184  !/
185  !/ Copyright 2009 National Weather Service (NWS),
186  !/ National Oceanic and Atmospheric Administration. All rights
187  !/ reserved. WAVEWATCH III is a trademark of the NWS.
188  !/ No unauthorized use without permission.
189  !/
190  !/ 1. Purpose :
191  ! Calculate ice source term S_{ice} according to 3 different sea ice
192  ! models (Mosig et al. 2015, Meylan et al. 2018, Liu et al. 2020)
193  !
194  ! 2. Method :
195  ! Regarding i/o (general to all Sice modules): S_{ice} source term
196  ! is calculated using up to 5 parameters read from input files.
197  ! These parameters are allowed to vary in space and time.
198  ! The parameters control the exponential decay rate k_i.
199  ! Since there are 5 parameters, this permits description of
200  ! dependence of k_i on frequency or wavenumber.
201  !
202  ! Sea ice affects the wavenumber k of wind-generated ocean waves.
203  ! The ice-modified wavenumber can be expressed as a complex number
204  ! k = k_r + i * k_i, with the real part k_r representing impact of
205  ! the sea ice on the physical wavelength and propagation speeds,
206  ! producing something analogous to shoaling and refraction by
207  ! bathymetry, whereas the imaginary part of the complex
208  ! wavenumber, k_i, is an exponential decay coefficient
209  ! k_i(x,y,t,sigma) (depending on location, time and frequency,
210  ! respectively), representing wave attenuation, and can be
211  ! introduced in a wave model such as WW3 as S_ice/E=-2*Cg*k_i,
212  ! where S_ice is one of several dissipation mechanisms, along
213  ! with whitecapping, for example, S_ds=S_wc+S_ice+⋯. The k_r -
214  ! modified by ice would enter the model via the C calculations
215  ! on the left-hand side of the governing equation.The fundamentals
216  ! are straightforward, e.g. Rogers and Holland (2009 and
217  ! subsequent unpublished work) modified a similar model, SWAN
218  ! (Booij et al. 1999) to include the effects of a viscous mud
219  ! layer using the same approach (k = k_r + i*k_i) previously.
220  !
221  ! General approach is analogous to Rogers and Holland (2009)
222  ! approach for mud.
223  ! See text near their eq. 1 :
224  ! k = k_r + i * k_i
225  ! eta(x,t) = Real( a * exp( i * ( k * x - sigma * t ) ) )
226  ! a = a0 * exp( -k_i * x )
227  ! S / E = -2 * Cg * k_i (see also Komen et al. (1994, pg. 170)
228  !
229  ! Following W3SBT1 as a guide, equation 1 of W3SBT1 says:
230  ! S = D * E
231  ! However, the code of W3SBT1 has
232  ! S = D * A
233  ! This leads me to believe that the calling routine is
234  ! expecting "S/sigma" not "S"
235  ! Thus we will use D = S/E = -2 * Cg * k_i
236  ! (see also documentation of W3SIC1)
237  !
238  ! Notes regarding numerics:
239  ! -------------------------
240  ! Experiments with constant k_i values suggest that results may be
241  ! dependent on resolution if insufficient resolution is used.
242  ! For detailed information, see documentation of W3SIC1.
243  !
244  ! Note regarding applicability/validity:
245  ! --------------------------------------
246  ! Similar to the Wang and Shen model used in w3sic3md, the 3 models
247  ! used here are empirical medium models as well which treat the sea
248  ! ice cover as a continuum and use 1/2 empirical rheological para-
249  ! meters, i.e., the effective shear modulus of ice G and the effec-
250  ! tive viscosity η to characterize sea ices of various type. Please
251  ! see the documentation of w3sic3md for a detailed discussion of
252  ! this kind of model.
253  !
254  ! 3. Parameters :
255  !
256  ! Parameter list
257  ! ----------------------------------------------------------------
258  ! A R.A. I Action density spectrum (1-D).
259  ! DEPTH Real I Local water depth.
260  ! CG R.A. I Group velocities.
261  ! WN R.A. I Wavenumbers
262  ! IX,IY I.S. I Grid indices.
263  ! S R.A. O Source term (1-D version).
264  ! D R.A. O Diagonal term of derivative (1-D version).
265  ! ----------------------------------------------------------------
266  !
267  ! 4. Subroutines used :
268  !
269  ! Name Type Module Description
270  ! ----------------------------------------------------------------
271  ! STRACE Subr. W3SERVMD Subroutine tracing (!/S switch).
272  ! PRT2DS Subr. W3ARRYMD Print plot output (!/T0 switch).
273  ! OUTMAT Subr. W3ARRYMD Matrix output (!/T1 switch).
274  ! W3IC5WNCG Subr. / Wavenumber and group velocity of ice-
275  ! coupled waves
276  ! ----------------------------------------------------------------
277  ! * / means this module
278  !
279  ! 5. Called by :
280  !
281  ! Name Type Module Description
282  ! ----------------------------------------------------------------
283  ! W3SRCE Subr. W3SRCEMD Source term integration.
284  ! W3EXPO Subr. N/A ASCII Point output post-processor.
285  ! W3EXNC Subr. N/A NetCDF Point output post-processor.
286  ! GXEXPO Subr. N/A GrADS point output post-processor.
287  ! ----------------------------------------------------------------
288  !
289  ! 6. Error messages :
290  !
291  ! None.
292  !
293  ! 7. Remarks :
294  !
295  ! If ice parameter 1 is zero, no calculations are made.
296  !
297  ! 8. Structure :
298  !
299  ! See source code.
300  !
301  ! 9. Switches :
302  !
303  ! !/S Enable subroutine tracing.
304  ! !/T Enable general test output.
305  ! !/T0 2-D print plot of source term.
306  ! !/T1 Print arrays.
307  !
308  ! 10. Source code :
309  !/ ------------------------------------------------------------------- /
310  !/
311 #ifdef W3_T
312  USE w3odatmd, ONLY: ndst
313 #endif
314 #ifdef W3_S
315  USE w3servmd, ONLY: strace
316 #endif
317 #ifdef W3_T0
318  USE w3arrymd, ONLY: prt2ds
319 #endif
320 #ifdef W3_T1
321  USE w3arrymd, ONLY: outmat
322 #endif
323  !/
324  USE constants, ONLY: tpi
325  USE w3servmd, ONLY: extcde
326  USE w3odatmd, ONLY: ndse, iaproc, naproc, naperr
327  USE w3gdatmd, ONLY: nk, nth, nspec, sig, mapwn, ic5pars
328  USE w3idatmd, ONLY: inflags2, icep1, icep2, icep3, icep4, icei
329  !
330  IMPLICIT NONE
331  !
332  !/
333  !/ ------------------------------------------------------------------- /
334  !/ Parameter list
335  !/
336  REAL, INTENT(IN) :: cg(nk), wn(nk), a(nspec), depth
337  REAL, INTENT(OUT) :: s(nspec), d(nspec)
338  INTEGER, INTENT(IN) :: ix, iy
339  !/ ------------------------------------------------------------------- /
340  !/ Local parameters
341  !/
342 #ifdef W3_S
343  INTEGER, SAVE :: ient = 0
344 #endif
345 #ifdef W3_T0
346  INTEGER :: ith
347  REAL :: dout(nk,nth)
348 #endif
349  !/
350  REAL :: icecoef1, icecoef2, icecoef3, &
351  icecoef4, iceconc
352  REAL, DIMENSION(NK) :: d1d, wn_r, wn_i
353  ! REAL :: TWN_R, TWN_I
354  INTEGER :: ik, ikth
355  LOGICAL :: noice
356  !/ ------------------------------------------------------------------- /
357  !/
358 #ifdef W3_S
359  CALL strace (ient, 'W3SIC5')
360 #endif
361  !
362  ! 0. Initializations ------------------------------------------------ /
363  d = 0.
364  d1d = 0.
365  wn_r = 0.
366  wn_i = 0.
367  !
368  icecoef1 = 0.
369  icecoef2 = 0.
370  icecoef3 = 0.
371  icecoef4 = 0.
372  iceconc = 0.
373  !
374  ! Set the ice parameters from input
375  IF (inflags2(-7)) THEN
376  icecoef1 = icep1(ix, iy) ! ice thickness h_i
377  ELSE
378  IF ( iaproc .EQ. naperr ) &
379  WRITE (ndse,1001) 'ICE PARAMETER 1 (HICE)'
380  CALL extcde(2)
381  ENDIF
382  !
383  IF (inflags2(-6)) THEN
384  icecoef2 = icep2(ix, iy) ! effective viscosity of ice η
385  ELSE
386  IF ( iaproc .EQ. naperr ) &
387  WRITE (ndse,1001) 'ICE PARAMETER 2 (VISC)'
388  CALL extcde(2)
389  ENDIF
390  !
391  IF (inflags2(-5)) THEN
392  icecoef3 = icep3(ix, iy) ! density of ice ρ_i
393  ELSE
394  IF ( iaproc .EQ. naperr ) &
395  WRITE (ndse,1001) 'ICE PARAMETER 3 (DENS)'
396  CALL extcde(2)
397  ENDIF
398  !
399  IF (inflags2(-4)) THEN
400  icecoef4 = icep4(ix, iy) ! effective shear modulus of ice G
401  ELSE
402  IF ( iaproc .EQ. naperr ) &
403  WRITE (ndse,1001) 'ICE PARAMETER 4 (ELAS)'
404  CALL extcde(2)
405  ENDIF
406  !
407  IF (inflags2(4)) iceconc = icei(ix, iy) ! ice concentration
408  !
409  ! 1. No ice --------------------------------------------------------- /
410  noice = .false.
411  ! Zero ice thickness
412  ! Very small ice thickness may cause problems in POLYROOTS because
413  ! the first coefficient C1 may be very close to zero. So we regard
414  ! cases where hice is less than 0.0001 as no ice.
415  ! IF (ICECOEF1 < ERRTOL) NOICE = .TRUE.
416  IF (icecoef1 < 0.0001) noice = .true.
417  ! zero ice concentration
418  IF (inflags2(4) .AND. iceconc < errtol) noice = .true.
419  !
420  ! Calculate the decay rate k_i
421  IF ( noice ) THEN
422  d1d = 0.
423  !
424  ! 2. Ice ------------------------------------------------------------- /
425  ELSE
426  ! W3IC5WNCG(WN_R, WN_I, CG, HICE, IVISC, RHOI, ISMODG, HWAT)
427  CALL w3ic5wncg(wn_r, wn_i, cg, icecoef1, icecoef2, &
428  icecoef3, icecoef4, depth)
429  ! recall that D=S/E=-2*Cg_{ice}*k_i
430  ! In some cases, the FS model yields very large Cg_{ice}, which
431  ! subquently may result in numerical failure due to the violation of CFL
432  ! conditions, therefore we still use ice-free group velocity to advect
433  ! wave packets.
434  !
435  DO ik = 1, nk
436  d1d(ik) = -2.0 * cg(ik) * wn_i(ik)
437  END DO
438  END IF
439  !
440  ! 2.1 Fill diagonal matrix
441  DO ikth = 1, nspec
442  d(ikth) = d1d(mapwn(ikth))
443  END DO
444 
445  s = d * a
446  !
447  ! ... Test output of arrays
448  !
449 #ifdef W3_T0
450  DO ik=1, nk
451  DO ith=1, nth
452  dout(ik,ith) = d(ith+(ik-1)*nth)
453  END DO
454  END DO
455  CALL prt2ds (ndst, nk, nk, nth, dout, sig(1:), ' ', 1., &
456  0.0, 0.001, 'Diag Sice', ' ', 'NONAME')
457 #endif
458  !
459 #ifdef W3_T1
460  CALL outmat (ndst, d, nth, nth, nk, 'diag Sice')
461 #endif
462  !
463  ! Formats
464  !
465 1001 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
466  ' ',a,' IS NOT DEFINED IN ww3_shel.inp.')
467 
468  !/
469  !/ End of W3SIC5------------------------------------------------------ /
470  !/
471  END SUBROUTINE w3sic5
472  !/ ------------------------------------------------------------------- /
473  !/
493  SUBROUTINE w3ic5wncg(WN_R, WN_I, CG, HICE, IVISC, RHOI, ISMODG, &
494  HWAT)
495  !/
496  !/ +-----------------------------------+
497  !/ | WAVEWATCH III NOAA/NCEP |
498  !/ | Q. Liu |
499  !/ | E. Rogers |
500  !/ | FORTRAN 90 |
501  !/ | Last update : 25-Apr-2017 |
502  !/ +-----------------------------------+
503  !/
504  !/ 17-Apr-2016 : Origination ( version 5.10)
505  !/ ( Q. Liu )
506  !/ 17-Apr-2016 : Start from W3IC3WNCG_CHENG ( Q. Liu )
507  !/
508  !/ 1. Purpose:
509  ! Calculation of complex wavenumber arrays for ice-coupled waves.
510  !
511  ! This also allows us to use Cg_ice in the advection part of the
512  ! radiative transfer energy equation (RTE). --- abandoned in the end
513  !
514  ! 2. Method:
515  ! Using the Fox-Squire dispersion relations to get (kr, ki) and
516  ! then get cg by cg = dσ / dk (here dk uses kr)
517  !
518  ! 3. Parameters:
519  !
520  ! Parameter list:
521  ! ----------------------------------------------------------------
522  ! Name Type Intent Description
523  ! ----------------------------------------------------------------
524  ! WN_R R.A. I/O the real. part of the wave number
525  ! WN_I R.A. I/O the imag. part of the wave number
526  ! CG R.A. I group velocity (m s^{-1})
527  ! HICE Real. I thickness of ice (m)
528  ! IVISC Real. I viscosity parameter of ice (m^2 s^{-1})
529  ! RHOI Real. I the density of ice (kg m^{-3})
530  ! ISMODG Real. I effecitive shear modulus G of ice (Pa)
531  ! HWAT Real. I water depth
532  ! ----------------------------------------------------------------
533  ! * the intent of WN_R/I must be inout
534  ! * CG is unchanged but still kept here because some legacy reasons.
535  !
536  ! 4. Subroutines used:
537  !
538  ! Name Type Module Description
539  ! ----------------------------------------------------------------
540  ! FSDISP Subr. / dispersion relations for ice-coupled waves
541  ! CGINICE5 Subr. / group velocity for given (σ, kr) array
542  ! ----------------------------------------------------------------
543  !
544  ! 5. Called by :
545  !
546  ! Name Type Module Description
547  ! ----------------------------------------------------------------
548  ! W3SIC5 Subr. Public Ice source term
549  ! W3WAVE Subr. W3WAVEMD WW3 integration
550  ! ----------------------------------------------------------------
551  !
552  ! 6. Error messages :
553  !
554  ! 7. Remarks :
555  !
556  ! 8. Structure :
557  !
558  ! See source code.
559  !
560  ! 9. Switches :
561  !
562  ! !/S Enable subroutine tracing.
563  !
564  ! 10. Source code :
565  !
566  !/ ------------------------------------------------------------------- /
567 #ifdef W3_S
568  USE w3servmd, ONLY: strace
569 #endif
570  USE constants, ONLY: tpi
571  USE w3gdatmd, ONLY: nk, sig
572  USE w3odatmd, ONLY: ndse, iaproc, naproc, naperr
573  USE w3servmd, ONLY: extcde
574  !/
575  IMPLICIT NONE
576  !/
577  !/ ------------------------------------------------------------------- /
578  !/ Parameter list
579  REAL, INTENT(INOUT) :: wn_r(:), wn_i(:)
580  REAL, INTENT(IN) :: cg(:)
581  REAL, INTENT(IN) :: hice, ivisc, rhoi, ismodg, hwat
582  !/
583  !/ ------------------------------------------------------------------- /
584  !/ Local parameters
585  REAL, ALLOCATABLE :: sigma(:)
586  INTEGER :: kl, ku, ik
587  REAL :: twn_r, twn_i
588  !/
589 #ifdef W3_S
590  INTEGER, SAVE :: ient = 0
591 #endif
592  !/
593  !/ ------------------------------------------------------------------- /
594  !/
595 #ifdef W3_S
596  CALL strace (ient, 'W3IC5WNCG')
597 #endif
598  !/
599  ! Initialize SIGMA {in w3gdatmd: SIG (0: NK+1)}
600  IF (ALLOCATED(sigma)) DEALLOCATE(sigma); ALLOCATE(sigma(SIZE(cg)))
601  sigma = 0.
602 
603  IF (SIZE(wn_r, 1) .EQ. nk) THEN
604  kl = 1
605  ku = nk
606  sigma = sig(1:nk)
607  ELSE IF (SIZE(wn_r,1) .EQ. nk+2) THEN
608  kl = 1
609  ku = nk+2
610  sigma = sig(0:nk+1)
611  ELSE
612  IF ( iaproc .EQ. naperr ) WRITE(ndse,900) 'W3IC5WNCG'
613  CALL extcde(3)
614  END IF
615  !
616  ! Fox-Squire dispersion
617  DO ik = kl, ku
618  ! FSDISP(HICE, IVISC, RHOI, ISMODG, HWAT, WT, WNR, WNI)
619  CALL fsdisp(hice, ivisc, rhoi, ismodg, hwat, tpi/sigma(ik), &
620  twn_r, twn_i)
621  wn_r(ik) = twn_r
622  wn_i(ik) = twn_i
623  END DO
624  !
625  DEALLOCATE(sigma)
626  !
627 900 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
628  ' Subr. ', a, ': Cannot determine bounds of&
629  & wavenumber array.'/)
630  !/
631  !/ End of W3IC5WNCG -------------------------------------------------- /
632  !/
633  END SUBROUTINE w3ic5wncg
634  !/ ------------------------------------------------------------------- /
635  !/
652  SUBROUTINE fsdisp(HICE, IVISC, RHOI, ISMODG, HWAT, WT, WNR, WNI)
653  !/
654  !/ +-----------------------------------+
655  !/ | WAVEWATCH III NOAA/NCEP |
656  !/ | Q. Liu |
657  !/ | FORTRAN 90 |
658  !/ | Last update : 19-May-2021 |
659  !/ +-----------------------------------+
660  !/
661  !/ 17-Mar-2016 : Origination ( version 5.10)
662  !/ ( Q. Liu)
663  !/ 17-Mar-2016 : Start from the Matlab code `FoxSquire.m` (provided
664  !/ by Prof. Vernon Squire from University of Otago)
665  !/ ( Q. Liu)
666  !/ 25-Apr-2017 : Add more filters ( Q. Liu)
667  !/
668  !/ 19-May-2021 : Incl. RP and M2 ice models ( Q. Liu)
669  !/
670  ! 1. Purpose :
671  !
672  ! Calculate the complex wavenumber for waves in ice according to
673  ! three different sea ice models, i.e., FS, RP and M2 (see Liu et
674  ! al. 2020)
675  !
676  ! 2. Method :
677  ! Mainly solving the dispersion relations of FS and RP models (
678  ! Eqs. (20, 24, 25)) in Mosig et al. (2015))
679  !
680  ! 3. Parameters :
681  !
682  ! Parameter list
683  ! ----------------------------------------------------------------
684  ! Name Type Intent Description
685  ! ----------------------------------------------------------------
686  ! HICE Real. IN thickness of ice (m)
687  ! IVISC Real. IN viscosity parameter of ice (m^2 s^{-1})
688  ! RHOI Real. IN the density of ice (kg m^{-3})
689  ! ISMODG Real. IN effecitive shear modulus G of ice (Pa)
690  ! HWAT Real. IN water depth
691  ! WT Real. IN wave period (s; 1/freq)
692  ! WNR Real. Out the real. part of the wave number
693  ! WNI Real. Out the imag. part of the wave number
694  ! ----------------------------------------------------------------
695  !
696  ! 4. Subroutines used :
697  !
698  ! Name Type Module Description
699  ! ----------------------------------------------------------------
700  ! STRACE Subr. W3SERVMD Subroutine tracing.
701  ! POLYROOTS Subr. / Find the roots of a general polynomial
702  ! NR_ROOT Func. / Newton-Raphson root finding
703  ! ----------------------------------------------------------------
704  !
705  ! 5. Called by :
706  !
707  ! Name Type Module Description
708  ! ----------------------------------------------------------------
709  ! W3IC5WNCG Subr. / Wavenumber and group velocity of ice-
710  ! coupled waves
711  ! ----------------------------------------------------------------
712  !
713  ! 6. Error messages :
714  !
715  ! See Format 1000, 1001, 1002
716  !
717  ! 7. Remarks :
718  !
719  ! 8. Structure :
720  !
721  ! See source code.
722  !
723  ! 9. Switches :
724  !
725  ! !/S Enable subroutine tracing.
726  !
727  ! 10. Source code :
728  !
729  !/ ------------------------------------------------------------------- /
730 #ifdef W3_S
731  USE w3servmd, ONLY: strace
732 #endif
733  !/
734  USE constants, ONLY: grav, tpi
735  USE w3dispmd, ONLY: wavnu1
736  USE w3servmd, ONLY: extcde
737  USE w3odatmd, ONLY: ndse, iaproc, naproc, naperr
738  USE w3gdatmd, ONLY: ic5pars
739  USE w3gsrumd, ONLY: w3inan
740  !/
741  IMPLICIT NONE
742  !/
743  !/ ------------------------------------------------------------------- /
744  !/ Parameter list
745  REAL, INTENT(IN) :: hice, ivisc, rhoi, ismodg, hwat, wt
746  REAL, INTENT(OUT) :: wnr, wni
747  !/
748  !/ ------------------------------------------------------------------- /
749  !/ Local parameters
750  !
751  REAL :: ic5minig, ic5minwt, ic5maxkratio, &
752  ic5maxki, ic5minhw, ic5vemod
753  REAL :: tismodg, twt, tratio, thw
754  REAL, PARAMETER :: nu = 0.3, rhow = 1025.
755  ! COMPLEX :: GV, C1
756  ! REAL :: SIGMA, C2, WNO, CGO, THKH, &
757  COMPLEX :: gv, c1, c2
758  REAL :: sigma, wno, cgo, thkh, &
759  rtrl(5), rtim(5), rtang(5)
760  INTEGER :: ireal
761  ! COMPLEX(KDPC) :: GUESS, CROOT, C1D
762  ! REAL(KDP) :: C2D, HWATD
763  COMPLEX(KDPC) :: guess, croot, c1d, c2d
764  REAL(kdp) :: hwatd
765  !/
766 #ifdef W3_S
767  INTEGER, SAVE :: ient = 0
768 #endif
769  !/
770  !/ ------------------------------------------------------------------- /
771  !/
772 #ifdef W3_S
773  CALL strace (ient, 'FSDISP')
774 #endif
775  ! Note, same as W3IC3WNCG_xx in w3sic3md :
776  ! HICE → ICE1
777  ! IVISC → ICE2
778  ! RHOI → ICE3
779  ! ISMODG → ICE4
780  ! 0. Initializations ------------------------------------------------ *
781  ! Set limiters
782  !
783  ! When G = 0, the FS method does not provide a solution. It is not
784  ! unexpected because the FS model is originally devised as a
785  ! thin elastic plate model in which elasticity is necessary.
786  !
787  ! The FS algorithm may also have issues for very short wave periods,
788  ! shallow waters and low G (e.g., T~3 s, d~10 m, hi~0.5 m, G<10^6 Pa)
789  !
790  ic5minig = ic5pars(1) ! Minimum G
791  ic5minwt = ic5pars(2) ! Minimum T
792  ic5maxkratio = ic5pars(3) ! Maximum k_{ow}/k_r
793  ic5maxki = ic5pars(4) ! Maximum k_i
794  ic5minhw = ic5pars(5) ! Minimum d
795  ic5vemod = ic5pars(9) ! Model selected 1: EFS, 2: RP, 3: M2
796  !
797  tismodg = max(ic5minig, ismodg)
798  twt = max(ic5minwt, wt)
799  thw = max(ic5minhw, hwat)
800  !
801  ! G <= 0. is not allowed
802  IF (abs(tismodg) < errtol) THEN
803  IF ( iaproc .EQ. naperr ) WRITE(ndse, 1000) 'FSDISP'
804  CALL extcde(1)
805  END IF
806  !
807  ! σ = 2π / T
808  sigma = tpi / twt
809  !
810  IF (abs(ic5vemod - 1.) < errtol) THEN
811  ! Complex shear modulus Gv = G - i σ ρ η (EFS model)
812  gv = cmplx(tismodg, -1. * sigma * rhoi * ivisc)
813  !
814  ! -------------------------------------------------------------------- *
815  ! Note that Eq. (24) in Mosig et al. (2015) can be written like below:
816  ! (c1 * k^5 + c2 * k) * tanh(HWAT*k) - 1 = 0
817  ! Most Important part of this module --------------------------------- *
818  c1 = gv * hice**3. / (6. * rhow * sigma**2.)
819  !
820  ! To be divided by (1-NU) or multiplied by (1+NU) ??
821  ! Beam model: then multiplied by (1+ν)
822  ! Plate model: then divided by (1-ν)
823  ! The beam version is more theoretically (J.E.M. Mosig, personal
824  ! communication, 2016), although there is only very marginal difference
825  ! between this two version as (1+NU = 1.3 and 1/(1-NU) ~ 1.4)
826  c1 = c1 * (1+nu)
827  ! C1 = C1 / (1-NU)
828  !
829  ! C2
830  ! C2 = GRAV / SIGMA**2. - RHOI * HICE / RHOW
831  c2 = cmplx(grav / sigma**2. - rhoi * hice / rhow, 0.)
832  !
833  ELSE IF (abs(ic5vemod - 2.) < errtol) THEN
834  ! See Appendix of Liu et al. (2020) - RP model
835  c1 = cmplx(tismodg * hice**3. * (1+nu) / (6. * rhow * sigma**2.), 0.)
836  c2 = cmplx(grav/sigma**2. - rhoi * hice / rhow, &
837  -1. * ivisc / (rhow * sigma))
838  !
839  ELSE IF (abs(ic5vemod - 3.) > errtol) THEN
840  WRITE(ndse, 1003) 'FSDISP', ic5vemod
841  CALL extcde(4)
842  END IF
843  ! Use the dispersion in open water to get an approximation of
844  ! tanh(HWAT * k). We can also roughly use the dispersion in deep
845  ! water case, that is tanh(HWAT*k) ~ 1.
846  ! Wavenumber in the open water
847  ! WAVNU1(SI, H, K, CG)
848  CALL wavnu1(sigma, thw, wno, cgo)
849  thkh = tanh(wno * thw)
850  !
851  IF (abs(ic5vemod - 1.) < errtol .OR. abs(ic5vemod - 2.) < errtol) THEN
852  ! Get the first guess of the complex wavenumber
853  CALL polyroots(6, &
854  (/real(real(c1))*thkh, 0., 0., 0., real(real(c2))*thkh, -1./),&
855  rtrl, rtim)
856  rtang = atan2(rtim, rtrl)
857  !
858  ! There should only be one real root in RTRL + i * RTIM because in
859  ! this case (ivisc=0) the original viscoelastic-type model reduced to
860  ! the thin elastic plate model which has only one real solution.
861  ! Find its index ...
862  !
863  ireal = minloc(abs(rtang), dim=1)
864  IF (rtrl(ireal) <= 0. .OR. abs(rtim(ireal)) > errtol) THEN
865  IF ( iaproc .EQ. naperr ) WRITE(ndse, 1001) 'FSDISP'
866  CALL extcde(2)
867  END IF
868  !
869  ! Get the first guess for iteration
870  guess = rtrl(ireal) * exp(cmplx(0., 1e-6))
871  !
872  ! Newton-Raphson method
873  ! Turn c1, c2, hwat to be double
874  c1d = c1; c2d = c2; hwatd = thw
875  croot = nr_root(c1d, c2d, hwatd, guess)
876  wnr = real(real(croot))
877  wni = real(aimag(croot))
878  !
879  ELSE IF (abs(ic5vemod - 3.) < errtol) THEN ! M2
880  ! Model with Order 3 Power Law (section 6.2 in Meylan et al. (2018, JGR-Ocean))
881  ! Based on my understanding, the wavelength does not change because
882  ! the elasticity is not considered in this model
883  wnr = wno ! Open-water wavenumber
884  ! Eq. (53) in Meylan et al. (2018)
885  wni = hice * ivisc * sigma**3. / (rhow * grav**2.)
886  END IF
887  !
888  ! RATIO Check
889  ! Using the ratio k0 / kr as a basic check for the reliability of
890  ! FSDISP. The FS dispersion relation can give a very different kr from
891  ! k0, especially for small wave periods (k0/kr is as high as 100).
892  ! From my tests, using IC5MAXKRATIO = 1000. can basically detect most
893  ! spurious solutions (although not all of them)
894  !
895  ! ISNAN Check
896  ! Common ways used are:
897  ! NAN = SQRT(-1.) or
898  ! a /= a then a is NaN or
899  ! ISNAN func (supported by gfortran & ifort)
900  ! --- ISNAN -> W3INAN because ISNAN is not supported by pgi
901  ! For very few cases, we can get nan | negative ki | kr
902  !
903  ! (N.B.) NaN problem solved by using CMPLX_TANH2
904  !
905  tratio = wno / wnr
906  IF (w3inan(wnr) .OR. w3inan(wni) .OR. wnr <= 0 .OR. wni <= 0. &
907  .OR. tratio >= ic5maxkratio) THEN
908  IF ( iaproc .EQ. naperr ) &
909  WRITE(ndse, 1002) 'FSDISP', hice, ivisc, tismodg, hwat, twt, &
910  wno, wnr, wni
911  CALL extcde(3)
912  END IF
913  !
914  ! Filter high ki
915  wni = min(ic5maxki, wni)
916  !
917  ! FORMAT
918 1000 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
919  ' Subr. ', a, ': Zero shear modulus G is not allowed&
920  & in the FS viscoelastic model'/)
921  !
922 1001 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
923  ' Subr. ', a, ': get a bad first guess'/)
924  !
925 1002 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
926  ' -----------------------------------------------------'/&
927  ' Subr. ', a,' : get NaN/NeG/Huge kr or ki for' /&
928  ' -----------------------------------------------------'/&
929  ' Ice thickness : ', f9.1, ' m'/ &
930  ' Ice viscosity : ', e9.2, ' m2/s'/ &
931  ' Ice shear modulus : ', e9.2, ' Pa' / &
932  ' Water depth : ', f9.1, ' m'/ &
933  ' Wave period : ', f10.2, ' s'/ &
934  ' Wave number (Ko) : ', f11.3, ' rad/m'/ &
935  ' Wave number (Kr) : ', f11.3, ' rad/m'/ &
936  ' Attenu. Rate (Ki) : ', e9.2, ' /m'/)
937  !
938 1003 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
939  ' Subr. ', a, ': Unknown VE model (', f5.0, ')'/)
940  !/
941  !/ End of FSDISP ----------------------------------------------------- /
942  !/
943  END SUBROUTINE fsdisp
944  !/ ------------------------------------------------------------------- /
945  !/
956  SUBROUTINE balancing_matrix(NMAT, MATRIX)
957  !/
958  !/ +-----------------------------------+
959  !/ | WAVEWATCH III NOAA/NCEP |
960  !/ | Q. Liu |
961  !/ | FORTRAN 90 |
962  !/ | Last update : 15-Mar-2016 |
963  !/ +-----------------------------------+
964  !/
965  !/ 15-Mar-2016 : Origination ( version 5.10)
966  !/ ( Q. Liu )
967  !/ 15-Mar-2016 : Borrowed from Numerical Recipes in Fortran
968  !/ ( Q. Liu )
969  ! 1. Purpose :
970  ! Reducing the sensitivity of eigenvalues to rounding errors during
971  ! the execution of some algorithms.
972  !
973  ! 2. Method :
974  ! The errors in the eigensystem found by a numerical procedure are
975  ! generally proportional to the Euclidean norm of the matrix, that
976  ! is, to the square root of the sum of the squares of the elements
977  ! (sqrt(sum(a_{i, j} ** 2.)). The idea of balancing is to use
978  ! similarity transformations to make corresponding rows and columns
979  ! of the matrix have comparable norms, thus reducing the overall
980  ! norm of the matrix while leaving the eigenvalues unchanged. Note
981  ! that the symmetric matrix is already balanced.
982  !
983  ! The output is matrix that is balanced in the norm given by
984  ! summing the absolute magnitudes of the matrix elements(
985  ! sum(abs(a_{i, j})) ). This is more efficient than using the
986  ! Euclidean norm, and equally effective: a large reduction in
987  ! one norm implies a large reduction in the other.
988  !
989  ! For the details of this method, please refer to
990  ! 1) Numerical Recipes in Fortran 77 (Volume 1, 2nd Edition)
991  ! [Chapter 11.5 / subroutine balanc]
992  ! 2) Numerical Recipes in Fortran 90 (Volume 2)
993  ! [Chapter B11 / subroutine balanc]
994  !
995  ! 3. Parameters :
996  !
997  ! Parameter list
998  ! ----------------------------------------------------------------
999  ! Name Type Intent Description
1000  ! ----------------------------------------------------------------
1001  ! NMAT Int. I The size of one dimension of MATRIX
1002  ! MATRIX R.A. I/O A matrix with the shape (NMAT, NMAT)
1003  ! ----------------------------------------------------------------
1004  !
1005  ! 4. Subroutines used :
1006  !
1007  ! Name Type Module Description
1008  ! ----------------------------------------------------------------
1009  ! STRACE Subr. W3SERVMD Subroutine tracing (!/S switch).
1010  ! ----------------------------------------------------------------
1011  !
1012  ! 5. Called by :
1013  !
1014  ! Name Type Module Description
1015  ! ----------------------------------------------------------------
1016  ! POLYROOTS Subr. / Find the roots of polynomials
1017  ! ----------------------------------------------------------------
1018  !
1019  ! 6. Error messages :
1020  !
1021  ! None.
1022  !
1023  ! 7. Remarks:
1024  ! Balancing only needs marginal computational efforts but can
1025  ! substantially improve the accuracy of the eigenvalues computed
1026  ! for a badly balanced matrix. It is therefore recommended that
1027  ! you always balance nonsymmetric matrices.
1028  !
1029  ! Given a (NMAT, NMAT) MATRIX, this routine replaces it by a
1030  ! balanced matrix with identical eigenvalues. A symmetric matrix is
1031  ! already balanced and is unaffected by this procedure.
1032  !
1033  ! 8. Structure :
1034  !
1035  ! See the source code.
1036  !
1037  ! 9. Switches :
1038  !
1039  ! !/S Enable subroutine tracing.
1040  !
1041  ! 10. Source code :
1042  !
1043  !/ ------------------------------------------------------------------- /
1044 #ifdef W3_S
1045  USE w3servmd, ONLY: strace
1046 #endif
1047  !
1048  IMPLICIT NONE
1049  !/
1050  !/ ------------------------------------------------------------------- /
1051  !/ Parameter list
1052  INTEGER, INTENT(IN) :: nmat
1053  REAL, INTENT(INOUT) :: matrix(nmat, nmat)
1054  !/ ------------------------------------------------------------------- /
1055  !/ Local parameter
1056 #ifdef W3_S
1057  INTEGER, SAVE :: ient = 0
1058 #endif
1059  ! the parameter radx is the machine's floating-point radix
1060  REAL, PARAMETER :: radx = radix(matrix), &
1061  sqradx = radx ** 2
1062  INTEGER :: i, last
1063  REAL :: c, f, g, r, s
1064  !/ ------------------------------------------------------------------- /
1065 #ifdef W3_S
1066  CALL strace (ient, 'BALANCING_MATRIX')
1067 #endif
1068  !
1069  DO
1070  last = 1
1071  DO i = 1, nmat
1072  ! Calculate row and column norms
1073  c = sum( abs(matrix(:, i)) ) - matrix(i, i)
1074  r = sum( abs(matrix(i, :)) ) - matrix(i, i)
1075  ! If both are non-zero
1076  IF (c /= 0.0 .AND. r /= 0.0) THEN
1077  ! Find the integer power of the machine radix that comes closest to
1078  ! balancing the matrix (get G, F from C, R)
1079  g = r / radx
1080  f = 1.0
1081  s = c + r
1082  DO
1083  IF (c >= g) EXIT
1084  f = f * radx
1085  c = c * sqradx
1086  END DO
1087  !
1088  g = r * radx
1089  DO
1090  IF (c <= g) EXIT
1091  f = f / radx
1092  c = c / sqradx
1093  END DO
1094  !
1095  IF ( (c+r)/f < 0.95*s) THEN
1096  last = 0
1097  g = 1.0 / f
1098  ! Apply similarity tranformation
1099  matrix(i, :) = matrix(i, :) * g
1100  matrix(:, i) = matrix(:, i) * f
1101  END IF
1102  END IF
1103  END DO
1104  IF (last /= 0) EXIT
1105  END DO
1106  !/
1107  !/ End of subroutine BALANCING_MATRIX -------------------------------- /
1108  !/
1109  END SUBROUTINE balancing_matrix
1110  !/ ------------------------------------------------------------------- /
1111  !/
1123  SUBROUTINE eig_hqr (NMAT, HMAT, EIGR, EIGI)
1124  !/
1125  !/ +-----------------------------------+
1126  !/ | WAVEWATCH III NOAA/NCEP |
1127  !/ | Q. Liu |
1128  !/ | FORTRAN 90 |
1129  !/ | Last update : 17-Mar-2016 |
1130  !/ +-----------------------------------+
1131  !/
1132  !/ 16-Mar-2016 : Origination ( version 5.10)
1133  !/ ( Q. Liu )
1134  !/ 16-Mar-2016 : Borrowed from Numerical Recipes in Fortran
1135  !/ ( Q. Liu )
1136  !/ 17-Mar-2016 : Update the NR code v2.08 to v2.10 ( Q. Liu )
1137  !/
1138  ! 1. Purpose :
1139  !
1140  ! When we calculate the eigenvalues of a general matrix, we first
1141  ! reduce the matrix to a simpler form (e.g., Hessenberg form) and
1142  ! then we perform the iterative procedures.
1143  !
1144  ! A upper Hessenberg matrix has zeros everywhere below the diagnal
1145  ! except for the first subdiagonal row. For example, in the 6x6
1146  ! case, the non-zero elements are:
1147  ! |x x x x x x|
1148  ! |x x x x x x|
1149  ! | x x x x x|
1150  ! | x x x x|
1151  ! | x x x|
1152  ! | x x|
1153  !
1154  ! This subroutine uses QR algorithm to get the eigenvalues of a
1155  ! Hessenberg matrix. So make sure the input array HMAT is a
1156  ! Hessenberg-type matrix.
1157  !
1158  ! 2. Method :
1159  ! QR algorithm for real Hessenberg matrices.
1160  ! (I did not understand this algorithm well, so I could not give
1161  ! any detailed explanations)
1162  !
1163  ! For the details of this HQR method, please refer to
1164  ! 1) Numerical Recipes in Fortran 77 (Volume 1, 2nd Edition)
1165  ! [Chapter 11.6 / subroutine hqr]
1166  ! 2) Numerical Recipes in Fortran 90 (Volume 2)
1167  ! [Chapter B11 / subroutine hqr]
1168  !
1169  ! Note that there is a bug in the `hqr` subroutine in NR v2.08.
1170  ! See http://numerical.recipes/latest-known-bugs.html. Please use
1171  ! the updated code in NR v2.10.
1172  !
1173  ! 3. Parameters :
1174  !
1175  ! Parameter list
1176  ! ----------------------------------------------------------------
1177  ! Name Type Intent Description
1178  ! ----------------------------------------------------------------
1179  ! NMAT Int. I the size of one dimension of HMAT
1180  ! HMAT R.A. I/O the Hessenberg-type matrix (NMAT, NMAT)
1181  ! EIGR R.A. O the real part of the N eigenvalues
1182  ! EIGI R.A. O the imag part of the N eigenvalues
1183  ! ----------------------------------------------------------------
1184  !
1185  ! 4. Subroutines used :
1186  !
1187  ! Name Type Module Description
1188  ! ----------------------------------------------------------------
1189  ! STRACE Subr. W3SERVMD Subroutine tracing.
1190  ! ----------------------------------------------------------------
1191  !
1192  ! 5. Called by :
1193  !
1194  ! Name Type Module Description
1195  ! ----------------------------------------------------------------
1196  ! POLYROOTS Subr. / Find the roots of polynomials
1197  ! ----------------------------------------------------------------
1198  !
1199  ! 6. Error messages :
1200  !
1201  ! See Format 1001
1202  !
1203  ! 7. Remarks :
1204  !
1205  ! 8. Structure :
1206  !
1207  ! See source code.
1208  !
1209  ! 9. Switches :
1210  !
1211  ! !/S Enable subroutine tracing.
1212  !
1213  ! 10. Source code :
1214  !
1215  !/ ------------------------------------------------------------------- /
1216 #ifdef W3_S
1217  USE w3servmd, ONLY: strace
1218 #endif
1219  !/
1220  USE w3servmd, ONLY: extcde
1221  USE w3odatmd, ONLY: ndse, iaproc, naproc, naperr
1222  !/
1223  IMPLICIT NONE
1224  !/
1225  !/ ------------------------------------------------------------------- /
1226  !/ Parameter list
1227  !/
1228  INTEGER, INTENT(IN) :: nmat
1229  REAL, INTENT(INOUT) :: hmat(nmat, nmat)
1230  REAL, INTENT(OUT) :: eigr(nmat), eigi(nmat)
1231  !/
1232  !/ ------------------------------------------------------------------- /
1233  !/ Local parameters
1234  !/
1235 #ifdef W3_S
1236  INTEGER, SAVE :: ient = 0
1237 #endif
1238  !/
1239  INTEGER :: i, its, k, l, m, nn, mnnk, idiag
1240  REAL :: anorm, p, q, r, s, t, u, v, w, x, y, z
1241  REAL :: pp(nmat)
1242  !/ ------------------------------------------------------------------- /
1243  !/
1244 #ifdef W3_S
1245  CALL strace (ient, 'EIG_HQR')
1246 #endif
1247  !
1248  ! Compute matrix norm for possible use in locating single small
1249  ! subdiagonal element.
1250  !
1251  ! Note the speciality of Hessenberg matrix :
1252  ! Elements below the diagonal are zeros except for the first
1253  ! subdiagonal row. It might be more accurate if we use a mask array
1254  ! to mask all zero elments.
1255  !
1256  anorm = sum(abs(hmat))
1257  nn = nmat
1258  ! Gets changed only by an exceptional shift.
1259  t = 0.0
1260  ! Begin search for next eigenvalue: "do while nn >= 1"
1261  DO
1262  IF (nn < 1) EXIT
1263  its=0
1264  ! Begin iteration
1265  iterate:DO
1266  ! Look for single small subdiagonal element.
1267  small: DO l=nn, 2, -1
1268  s = abs( hmat(l-1, l-1) ) + abs( hmat(l, l) )
1269  ! IF (S == 0.0) S = ANORM
1270  IF (abs(s) < errtol) s = anorm
1271  ! IF ( ABS(HMAT(L, L-1)) + S == S ) THEN
1272  IF ( abs(hmat(l, l-1)) < errtol ) THEN
1273  hmat(l, l-1) = 0.0
1274  EXIT small
1275  END IF
1276  END DO small
1277  x = hmat(nn, nn)
1278  ! One root found
1279  IF (l == nn) THEN
1280  eigr(nn) = x + t
1281  eigi(nn) = 0.0
1282  nn=nn-1
1283  ! Go back for next eigenvalue
1284  EXIT iterate
1285  END IF
1286  y = hmat(nn-1, nn-1)
1287  w = hmat(nn, nn-1) * hmat(nn-1, nn)
1288  ! Two roots found . . .
1289  IF (l == nn-1) THEN
1290  p = 0.5 * (y - x)
1291  q = p**2 + w
1292  z = sqrt( abs(q) )
1293  x = x + t
1294  ! . . . A real pair . . .
1295  IF (q >= 0.0) THEN
1296  z = p + sign(z, p)
1297  eigr(nn) = x + z
1298  eigr(nn-1) = eigr(nn)
1299  IF (z /= 0.0) eigr(nn) = x - w/z
1300  eigi(nn) = 0.0
1301  eigi(nn-1) = 0.0
1302  ! . . . A complex pair
1303  ELSE
1304  eigr(nn) = x + p
1305  eigr(nn-1) = eigr(nn)
1306  eigi(nn) = z
1307  eigi(nn-1) = -z
1308  END IF
1309  nn=nn-2
1310  ! GO BACK FOR NEXT EIGENVALUE.
1311  EXIT iterate
1312  END IF
1313  ! NO ROOTS FOUND. CONTINUE ITERATION.
1314  IF (its == 30) THEN
1315  IF ( iaproc .EQ. naperr ) WRITE(ndse, 1001) 'EIG_HQR'
1316  CALL extcde(2)
1317  END IF
1318  ! FORM EXCEPTIONAL SHIFT.
1319  IF (its == 10 .OR. its == 20) THEN
1320  t = t + x
1321  ! Add -X to the diagonal of HMAT
1322  DO idiag = 1, nn
1323  hmat(idiag, idiag) = hmat(idiag, idiag) + (-x)
1324  END DO
1325  s = abs(hmat(nn, nn-1)) + abs(hmat(nn-1, nn-2))
1326  x = 0.75 * s
1327  y = x
1328  w = -0.4375 * s**2
1329  END IF
1330  its = its + 1
1331  ! Form shift and then look for 2 consecutive small subdiagonal elements.
1332  DO m = nn-2, l, -1
1333  z = hmat(m, m)
1334  r = x - z
1335  s = y - z
1336  ! Equation (11.6.23).
1337  p = (r * s - w) / hmat(m+1, m) + hmat(m, m+1)
1338  q = hmat(m+1, m+1) - z - r - s
1339  r = hmat(m+2, m+1)
1340  ! Scale to prevent overflow or underflow
1341  s = abs(p) + abs(q) + abs(r)
1342  p = p / s
1343  q = q / s
1344  r = r / s
1345  IF (m == l) EXIT
1346  u = abs( hmat(m, m-1) ) * ( abs(q) + abs(r) )
1347  v = abs(p) * ( abs(hmat(m-1, m-1)) + abs(z) + &
1348  abs( hmat(m+1, m+1) ))
1349  ! Equation (11.6.26)
1350  IF (u+v == v) EXIT
1351  END DO
1352  DO i= m+2, nn
1353  hmat(i, i-2) = 0.0
1354  IF (i /= m+2) hmat(i, i-3)=0.0
1355  END DO
1356  ! Double QR step on rows L to NN and columns M to NN
1357  DO k=m, nn-1
1358  IF (k /= m) THEN
1359  ! Begin setup of householder vector
1360  p = hmat(k, k-1)
1361  q = hmat(k+1, k-1)
1362  r = 0.0
1363  IF (k /= nn-1) r = hmat(k+2, k-1)
1364  x = abs(p) + abs(q) + abs(r)
1365  IF (x /= 0.0) THEN
1366  ! Scale to prevent overflow or underflow
1367  p = p / x
1368  q = q / x
1369  r = r / x
1370  END IF
1371  END IF
1372  s = sign(sqrt(p**2 + q**2 + r**2), p)
1373  IF (s /= 0.0) THEN
1374  IF (k == m) THEN
1375  IF (l /= m) hmat(k, k-1) = -hmat(k, k-1)
1376  ELSE
1377  hmat(k, k-1) = -s * x
1378  END IF
1379  ! Equations (11.6.24).
1380  p = p + s
1381  x = p / s
1382  y = q / s
1383  z = r / s
1384  q = q / p
1385  ! READY FOR ROW MODIFICATION.
1386  r = r / p
1387  pp(k:nn) = hmat(k, k:nn) + q * hmat(k+1, k:nn)
1388  IF (k /= nn-1) THEN
1389  pp(k:nn) = pp(k:nn) + r * hmat(k+2, k:nn)
1390  hmat(k+2, k:nn) = hmat(k+2, k:nn) - &
1391  pp(k:nn)*z
1392  END IF
1393  hmat(k+1, k:nn) = hmat(k+1, k:nn) - pp(k:nn) * y
1394  hmat(k, k:nn) = hmat(k, k:nn) - pp(k:nn) * x
1395  ! COLUMN MODIFICATION.
1396  mnnk = min(nn, k+3)
1397  pp(l:mnnk) = x * hmat(l:mnnk, k) + y * &
1398  hmat(l:mnnk, k+1)
1399  IF (k /= nn-1) THEN
1400  pp(l:mnnk) = pp(l:mnnk) + z*hmat(l:mnnk, k+2)
1401  hmat(l:mnnk, k+2) = hmat(l:mnnk, k+2) - &
1402  pp(l:mnnk) * r
1403  END IF
1404  hmat(l:mnnk, k+1) = hmat(l:mnnk, k+1) - &
1405  pp(l:mnnk) * q
1406  hmat(l:mnnk, k) = hmat(l:mnnk, k) - pp(l:mnnk)
1407  END IF
1408  END DO
1409  ! GO BACK FOR NEXT ITERATION ON CURRENT EIGENEND DO VALUE.
1410  END DO iterate
1411  END DO
1412  !
1413  ! Formats
1414 1001 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
1415  ' Subr. ', a, ': TOO MANY ITERATIONS'/)
1416  !/ ------------------------------------------------------------------- /
1417  !/
1418  !/ End of EIG_HQR ---------------------------------------------------- /
1419  !/
1420  END SUBROUTINE eig_hqr
1421  !/ ------------------------------------------------------------------- /
1422  !/
1435  SUBROUTINE polyroots(NPC, PCVEC, RTRL, RTIM)
1436  !/
1437  !/ +-----------------------------------+
1438  !/ | WAVEWATCH III NOAA/NCEP |
1439  !/ | Q. Liu |
1440  !/ | FORTRAN 90 |
1441  !/ | Last update : 16-Mar-2016 |
1442  !/ +-----------------------------------+
1443  !/
1444  !/ 16-Mar-2016 : Origination ( version 5.10)
1445  !/ ( Q. Liu )
1446  !/ 16-Mar-2016 : Started from Numerical Recipes in Fortran
1447  !/ ( Q. Liu )
1448  !/
1449  ! 1. Purpose :
1450  !
1451  ! Find the roots of arbitrary polynomials through finding the
1452  ! eigenvalues of companion matrix.
1453  !
1454  ! 2. Method :
1455  ! Suppose we have a general polynomial, which reads
1456  ! P(x) = c_n * x^n + c_{n-1} * x^{n-1} + ... + c_1 * x + c_0
1457  !
1458  ! Then finding the roots of P(x) is equivalent to find the eigen-
1459  ! values of the special n x n companion matrix A
1460  ! | -c_{n-1}/c_n -c_{n-2}/c_n ... -c_1/c_n -c_0/c_n |
1461  ! | 1 0 ... 0 0 |
1462  ! A = | 0 1 ... 0 0 |
1463  ! | : : : : |
1464  ! | 0 0 1 0 |
1465  !
1466  ! In fact, P(x) is the characteristic polynomial of matrix A, i.e.,
1467  ! P(x) = det|A-xI| and x is the eigenvalues of A (this is a
1468  ! Hessenberg matrix).
1469  !
1470  ! In this subrountine, we will use the two subroutines above
1471  ! (BALANCING_MATRIX & EIG_HQR) to get the complex eigenvalues of
1472  ! an abitrary Hessenberg matrix
1473  !
1474  ! For the details of this method, please refer to
1475  ! 1) Numerical Recipes in Fortran 77 (Volume 1, 2nd Edition)
1476  ! [Chapter 9.5 / Eigenvalue Methods / subroutine zrhqr]
1477  ! 2) Numerical Recipes in Fortran 90 (Volume 2)
1478  ! [Chapter B9 / subroutine zrhqr]
1479  !
1480  ! 3. Parameters :
1481  !
1482  ! Parameter list
1483  ! ----------------------------------------------------------------
1484  ! Name Type Intent Description
1485  ! ----------------------------------------------------------------
1486  ! NPC Int. I The # of the Polynomial coefficients
1487  ! (from c_n to c_0)
1488  ! PCVEC R.A. I The 1d vector for the Polynomial
1489  ! coefficients [c_n, c_{n-1}, ..., c_0]
1490  ! RTRL R.A. O The real part of all of the roots
1491  ! shape: [NPC-1]
1492  ! RTIM R.A. O The real part of all of the roots
1493  ! shape: [NPC-1]
1494  ! ----------------------------------------------------------------
1495  !
1496  ! 4. Subroutines used :
1497  !
1498  ! Name Type Module Description
1499  ! ------------------------------------- ---------------------------
1500  ! STRACE Subr. W3SERVMD Subroutine tracing.
1501  ! BALANCING_MATRIX Subr. / Balancing matrix
1502  ! EIG_HQR Subr. / Finding eigenvalues
1503  ! ----------------------------------------------------------------
1504  !
1505  ! 5. Called by :
1506  !
1507  ! Name Type Module Description
1508  ! ----------------------------------------------------------------
1509  ! FSDISP Subr. / Solving the dispersion relations
1510  ! ----------------------------------------------------------------
1511  !
1512  ! 6. Error messages :
1513  !
1514  ! See Format 1001
1515  !
1516  ! 7. Remarks :
1517  ! The built-in MATLAB function <roots> uses the same method to
1518  ! find roots of a general polynomial. But perhaps MATLAB uses
1519  ! different methods to find eigenvalues of the companion matrix.
1520  !
1521  ! 8. Structure :
1522  !
1523  ! See source code.
1524  !
1525  ! 9. Switches :
1526  !
1527  ! !/S Enable subroutine tracing.
1528  !
1529  ! 10. Source code :
1530  !
1531  !/ ------------------------------------------------------------------- /
1532 #ifdef W3_S
1533  USE w3servmd, ONLY: strace
1534 #endif
1535  !/
1536  USE w3servmd, ONLY: extcde
1537  USE w3odatmd, ONLY: ndse, iaproc, naproc, naperr
1538  IMPLICIT NONE
1539  !/
1540  !/ ------------------------------------------------------------------- /
1541  !/ Parameter list
1542  INTEGER, INTENT(IN) :: npc
1543  REAL, INTENT(IN) :: pcvec(npc)
1544  REAL, INTENT(OUT) :: rtrl(npc-1), rtim(npc-1)
1545  !/
1546  !/
1547  !/ ------------------------------------------------------------------- /
1548  !/ Local parameters
1549  !/
1550 #ifdef W3_S
1551  INTEGER, SAVE :: ient = 0
1552 #endif
1553  REAL :: hess(npc-1, npc-1)
1554  INTEGER :: j
1555  !/
1556  !/ ------------------------------------------------------------------- /
1557  !/
1558 #ifdef W3_S
1559  CALL strace (ient, 'POLYROOTS')
1560 #endif
1561  !
1562  !
1563  IF (abs(pcvec(1)) < errtol) THEN
1564  IF ( iaproc .EQ. naperr ) WRITE(ndse, 1001) 'POLYROOTS'
1565  CALL extcde(2)
1566  END IF
1567  !
1568  ! Generate the Hessenberg matrix
1569  hess = 0.
1570  hess(1, :) = -1 * pcvec(2:) / pcvec(1)
1571  DO j = 1, npc-2
1572  hess(j+1, j) = 1.
1573  END DO
1574 
1575  ! Balancing the matrix HESS
1576  CALL balancing_matrix(npc-1, hess)
1577  ! Eigenvalues of the matrix HESS
1578  CALL eig_hqr(npc-1, hess, rtrl, rtim)
1579 
1580  ! Formats
1581 1001 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
1582  ' Subr. ', a, ': the coeff. of x^n must not be 0'/)
1583  !/
1584  !/ End of POLYROOTS -------------------------------------------------- /
1585  !/
1586  END SUBROUTINE polyroots
1587  !/ ------------------------------------------------------------------- /
1588  !/
1602  FUNCTION nr_corr(K, C1, C2, H)
1603  !/
1604  !/ +-----------------------------------+
1605  !/ | WAVEWATCH III NOAA/NCEP |
1606  !/ | Q. Liu |
1607  !/ | FORTRAN 90 |
1608  !/ | Last update : 19-May-2021 |
1609  !/ +-----------------------------------+
1610  !/
1611  !/ 18-Mar-2016 : Origination. ( version 5.10 )
1612  !/ ( Q. Liu )
1613  !/ 18-Mar-2016 : Start from the Matlab code `FoxSquire.m` (provided
1614  !/ by Prof. Vernon Squire from University of Otago)
1615  !/ ( Q. Liu )
1616  !/ 24-Mar-2016 : Adding the cmplx_sinh/cosh/tanh ( Q. Liu )
1617  !/
1618  !/ 19-May-2021 : Change types of few input arguments ( Q. Liu )
1619  !/
1620  ! 1. Purpose :
1621  !
1622  ! Calculate the corrected term in the Newton-Raphson root-finding
1623  ! method (Must use double precision)
1624  !
1625  ! 2. Method :
1626  ! Suppose we want to find the root of f(x) = 0, then according to
1627  ! the Newton-Raphson method, the root is iteratively updated by the
1628  ! formula below:
1629  !
1630  ! x_{i+1} = x_{i} - f(x_{i}) / f'(x_{i}),
1631  !
1632  ! where f'(x) denotes the derivative of f(x). In this function,
1633  ! our f(x) reads (see also subr. FSDISP)
1634  !
1635  ! f(x) = (c1 * k**4 + c2) * k * tanh(kH) -1
1636  !
1637  ! we finally will get the Newton-Raphson correted term, i.e.,
1638  !
1639  ! dx = f(x_{i}) / f'(x_{i})
1640  !
1641  ! For the details of this method, please refer to
1642  ! 1) Numerical Recipes in Fortran 77 (Volume 1, 2nd Edition)
1643  ! Chapter 9.4
1644  !
1645  ! 3. Parameters :
1646  !
1647  ! Parameter list
1648  ! ----------------------------------------------------------------
1649  ! Name Type Intent Description
1650  ! ----------------------------------------------------------------
1651  ! K CMPL.(D) I complex wave number
1652  ! C1 CMPL.(D) I C1 in FSDISP
1653  ! C2 Real.(D) I C2 in FSDISP
1654  ! H Real.(D) I water depth
1655  ! NR_CORR CMPL.(D) O Newton-Raphson corrected term (DK)
1656  ! ----------------------------------------------------------------
1657  ! * (D) means double precision
1658  !
1659  ! 4. Subroutines used :
1660  !
1661  ! Name Type Module Description
1662  ! ----------------------------------------------------------------
1663  ! STRACE Subr. W3SERVMD Subroutine tracing.
1664  ! CMPLX_SINH Func. / sinh for complex var.
1665  ! CMPLX_COSH Func. / cosh for complex var.
1666  ! CMPLX_TANH2 Func. / tanh for complex var.
1667  ! ----------------------------------------------------------------
1668  !
1669  ! 5. Called by :
1670  !
1671  ! Name Type Module Description
1672  ! ----------------------------------------------------------------
1673  ! NR_ROOT Func. / Newton-Raphson root finding.
1674  ! ----------------------------------------------------------------
1675  !
1676  ! 6. Error messages :
1677  !
1678  ! None.
1679  !
1680  ! 7. Remarks :
1681  !
1682  ! 8. Structure :
1683  !
1684  ! See source code.
1685  !
1686  ! 9. Switches :
1687  !
1688  ! !/S Enable subroutine tracing.
1689  !
1690  ! 10. Source code :
1691  !
1692  !/ ------------------------------------------------------------------- /
1693 #ifdef W3_S
1694  USE w3servmd, ONLY: strace
1695 #endif
1696  !/
1697  IMPLICIT NONE
1698  !/
1699  !/ ------------------------------------------------------------------- /
1700  !/ Parameter list
1701  ! COMPLEX(KDPC), INTENT(IN) :: K, C1
1702  ! REAL(KDP), INTENT(IN) :: C2, H
1703  COMPLEX(KDPC), INTENT(IN) :: k, c1, c2
1704  REAL(kdp), INTENT(IN) :: h
1705  COMPLEX(KDPC) :: nr_corr
1706  !/
1707  !/
1708  !/ ------------------------------------------------------------------- /
1709  !/ Local parameters
1710  !/
1711 #ifdef W3_S
1712  INTEGER, SAVE :: ient = 0
1713 #endif
1714  ! A rough value to differentiate deep water case from finite water case
1715  REAL(kdp), PARAMETER :: kh_lim = 7.5
1716  COMPLEX(KDPC) :: lam, lampr, fv, df, tkh
1717  !/
1718  !/ ------------------------------------------------------------------- /
1719  !/
1720 #ifdef W3_S
1721  CALL strace (ient, 'NR_CORR')
1722 #endif
1723  ! f(k) = (c1 * k**4 + c2) * k * tanh(k*H) - 1
1724  ! = lam * k * tanh(k*H) - 1
1725  !
1726  tkh = k * h
1727  lam = c1 * k**4 + c2
1728  ! the derivative of (lam * k)
1729  lampr = 5 * c1 * k**4 + c2
1730  !
1731  IF (real(real(tkh)) <= kh_lim) THEN
1732  ! KH is small enough
1733  ! FV = LAM * K * SINH(K*H) - COSH(K*H)
1734  ! DF = LAM * (K*H) * COSH(K*H) + (LAMPR - H) * SINH(K*H)
1735  fv = lam * k * cmplx_sinh(tkh) - cmplx_cosh(tkh)
1736  df = lam * tkh * cmplx_cosh(tkh) + (lampr-h) * cmplx_sinh(tkh)
1737  ELSE
1738  ! FV = LAM * K * TANH(K*H) - 1
1739  ! DF = LAM * K * H + (LAMPR - H) * TANH(K*H)
1740  ! DF = LAMPR * TANH(K*H) + LAM * K * H / (COSH(K*H) **2)
1741  fv = lam * k * cmplx_tanh2(tkh) - 1
1742  df = lampr * cmplx_tanh2(tkh) + lam * tkh * &
1743  (1 - cmplx_tanh2(tkh) ** 2.)
1744  END IF
1745  !
1746  nr_corr = fv / df
1747  !/
1748  !/ End of NR_CORR ---------------------------------------------------- /
1749  !/
1750  END FUNCTION nr_corr
1751  !/ ------------------------------------------------------------------- /
1752  !/
1765  FUNCTION nr_root(C1, C2, H, GUESS)
1766  !/
1767  !/ +-----------------------------------+
1768  !/ | WAVEWATCH III NOAA/NCEP |
1769  !/ | Q. Liu |
1770  !/ | FORTRAN 90 |
1771  !/ | Last update : 19-May-2021 |
1772  !/ +-----------------------------------+
1773  !/
1774  !/ 18-Mar-2016 : Origination. ( version 5.10 )
1775  !/ ( Q. Liu )
1776  !/ 18-Mar-2016 : Start from the Matlab code `FoxSquire.m` (provided
1777  !/ by Prof. Vernon Squire from University of Otago)
1778  !/ ( Q. Liu )
1779  !/
1780  !/ 19-May-2021 : Change types of few input arguments ( Q. Liu )
1781  !/
1782  ! 1. Purpose :
1783  !
1784  ! The iterative procedure of the Newton-Raphson method
1785  !
1786  ! 2. Method :
1787  ! See the document of Subr. NR_CORR (Must use double precision)
1788  !
1789  ! 3. Parameters :
1790  !
1791  ! Parameter list
1792  ! ----------------------------------------------------------------
1793  ! Name Type Intent Description
1794  ! ----------------------------------------------------------------
1795  ! C1 CMPL.(D) I C1 in FS dipsersion relations
1796  ! See the doc. of subr. NR_CORR
1797  ! C2 REAL (D) I C2 in FS dipsersion relations
1798  ! H REAL (D) I water depth
1799  ! GUESS CMPL.(D) I the first guess obtained from POLYROOTS
1800  ! NR_ROOT CMPL.(D) O the calculated complex wave number.
1801  ! ----------------------------------------------------------------
1802  ! * (D) means double precision
1803  !
1804  ! 4. Subroutines used :
1805  !
1806  ! Name Type Module Description
1807  ! ----------------------------------------------------------------
1808  ! STRACE Subr. W3SERVMD Subroutine tracing.
1809  ! NR_CORR Func. / Newton-Raphson correction term
1810  ! INIT_RANDOM_SEED
1811  ! Subr. / Initialize the random seed based on
1812  ! the system's time
1813  ! ----------------------------------------------------------------
1814  !
1815  ! 5. Called by :
1816  !
1817  ! Name Type Module Description
1818  ! ----------------------------------------------------------------
1819  ! FSDISP Subr. / Solve FS dispersion relations
1820  ! ----------------------------------------------------------------
1821  !
1822  ! 6. Error messages :
1823  !
1824  ! None.
1825  !
1826  ! 7. Remarks :
1827  !
1828  ! 8. Structure :
1829  !
1830  ! See source code.
1831  !
1832  ! 9. Switches :
1833  !
1834  ! !/S Enable subroutine tracing.
1835  !
1836  ! 10. Source code :
1837  !
1838  !/ ------------------------------------------------------------------- /
1839 #ifdef W3_S
1840  USE w3servmd, ONLY: strace
1841 #endif
1842  !/
1843  USE w3servmd, ONLY: extcde
1844  USE w3odatmd, ONLY: ndse, iaproc, naproc, naperr
1845  USE w3gdatmd, ONLY: ic5pars
1846  !/
1847  IMPLICIT NONE
1848  !/
1849  !/ ------------------------------------------------------------------- /
1850  !/ Parameter list
1851  !/
1852  ! COMPLEX(KDPC), INTENT(IN) :: C1, GUESS
1853  ! REAL(KDP), INTENT(IN) :: C2, H
1854  COMPLEX(KDPC), INTENT(IN) :: c1, guess, c2
1855  REAL(kdp), INTENT(IN) :: h
1856  COMPLEX(KDPC) :: nr_root
1857  !/
1858  !/ ------------------------------------------------------------------- /
1859  !/ Local parameters
1860  !/
1861 #ifdef W3_S
1862  INTEGER, SAVE :: ient = 0
1863 #endif
1864  COMPLEX(KDPC) :: k0, k1, dk
1865  INTEGER :: iter
1866  REAL :: tranval
1867  REAL :: ic5maxiter, ic5rkick, ic5kfilter
1868  !/
1869  !/ ------------------------------------------------------------------- /
1870  !/
1871 #ifdef W3_S
1872  CALL strace (ient, 'NR_ROOT')
1873 #endif
1874  !/ Set parameters
1875  ic5maxiter = ic5pars(6)
1876  ic5rkick = ic5pars(7) ! 0: False, 1: True
1877  ic5kfilter = ic5pars(8)
1878  !
1879  k0 = guess
1880  dk = nr_corr(k0, c1, c2, h)
1881  k1 = k0 - dk
1882  iter = 0
1883 
1884  IF (ic5rkick > 0.5) CALL init_random_seed()
1885  !
1886  DO WHILE (abs(dk) > errtol)
1887  k0 = k1
1888  dk = nr_corr(k0, c1, c2, h)
1889  k1 = k0 - dk
1890  iter = iter + 1
1891  !
1892  ! Random kick to avoid converging to evanescent modes
1893  ! Note: do not use RAND(1) because it alway gives a same random no.
1894  ! The built in function of RAND is not available in <ifort>, use
1895  ! random_seed/number instead.
1896  !
1897  ! Based on many tests, I found the random kick & the corridor excluded
1898  ! from imaginary axis are kind of helpful to avoid spurious solutions.
1899  ! However, it may also lead to no solutions returned, especially for
1900  ! high G and high T.
1901  !
1902  IF (ic5rkick > 0.5 .AND. abs(real(k1)) < ic5kfilter) THEN
1903  ! K1 = K1 + 2*RAND(0)
1904  CALL random_number(tranval)
1905  k1 = k1 + 2 * tranval
1906  END IF
1907  !
1908  IF (iter >= ic5maxiter) THEN
1909  IF ( iaproc .EQ. naperr ) WRITE(ndse, 1001) 'NR_ROOT'
1910  CALL extcde(1)
1911  END IF
1912  !
1913  END DO
1914  !
1915  nr_root = k1
1916  !
1917  ! Formats
1918 1001 FORMAT(/' *** WAVEWATCH III ERROR IN W3SIC5MD : '/ &
1919  ' Subr. ', a, ': TOO MANY ITERATIONS'/)
1920  !
1921  !/
1922  !/ End of NR_ROOT ---------------------------------------------------- /
1923  !/
1924  END FUNCTION nr_root
1925  !/ ------------------------------------------------------------------- /
1926  !/
1940  FUNCTION cmplx_sinh(X)
1941  !/
1942  !/ +-----------------------------------+
1943  !/ | WAVEWATCH III NOAA/NCEP |
1944  !/ | Q. Liu |
1945  !/ | FORTRAN 90 |
1946  !/ | Last update : 24-Mar-2016 |
1947  !/ +-----------------------------------+
1948  !/
1949  !/ 24-Mar-2016 : Origination. ( version 5.10 )
1950  !/ ( Q. Liu )
1951  !/
1952  ! 1. Purpose :
1953  !
1954  ! For a number of compilers, the built-in function sinh, cosh and
1955  ! tanh do not support the complex inputs. So here I write an
1956  ! external one.
1957  !
1958  ! 2. Method :
1959  !
1960  ! sinh(x) = (e**x - e**(-x)) / 2 (The built in function exp supports
1961  ! complex input)
1962  !
1963  ! 3. Parameters :
1964  !
1965  ! Parameter list
1966  ! ----------------------------------------------------------------
1967  ! Name Type Intent Description
1968  ! ----------------------------------------------------------------
1969  ! X CMPL(D) I a double-precision complex var.
1970  ! ----------------------------------------------------------------
1971  ! * Note, this subr. will be only called by NR_CORR,
1972  ! so for simplicity, I only use double-precision complex var.
1973  ! as input.
1974  !
1975  ! 4. Subroutines used :
1976  !
1977  ! Name Type Module Description
1978  ! ----------------------------------------------------------------
1979  ! STRACE Subr. W3SERVMD Subroutine tracing.
1980  ! ----------------------------------------------------------------
1981  !
1982  ! 5. Called by :
1983  !
1984  ! Name Type Module Description
1985  ! ----------------------------------------------------------------
1986  ! NR_CORR Subr. / Newton-Raphson correction term.
1987  ! ----------------------------------------------------------------
1988  !
1989  ! 6. Error messages :
1990  !
1991  ! None.
1992  !
1993  ! 7. Remarks :
1994  !
1995  ! 8. Structure :
1996  !
1997  ! See source code.
1998  !
1999  ! 9. Switches :
2000  !
2001  ! !/S Enable subroutine tracing.
2002  !
2003  ! 10. Source code :
2004  !
2005  !/ ------------------------------------------------------------------- /
2006 #ifdef W3_S
2007  USE w3servmd, ONLY: strace
2008 #endif
2009  !/
2010  IMPLICIT NONE
2011  !/
2012  !/ ------------------------------------------------------------------- /
2013  !/ Parameter list
2014  !/
2015  COMPLEX(KDPC), INTENT(IN) :: x
2016  COMPLEX(KDPC) :: cmplx_sinh
2017  !/
2018  !/ ------------------------------------------------------------------- /
2019  !/ Local parameters
2020  !/
2021 #ifdef W3_S
2022  INTEGER, SAVE :: ient = 0
2023 #endif
2024  !/
2025  !/ ------------------------------------------------------------------- /
2026 #ifdef W3_S
2027  CALL strace (ient, 'CMPLX_SINH')
2028 #endif
2029  !/
2030  cmplx_sinh = (exp(x) - exp(-x)) * 0.5
2031  !/
2032  !/ End of CMPLX_SINH ------------------------------------------------- /
2033  !/
2034  END FUNCTION cmplx_sinh
2035  !/ ------------------------------------------------------------------- /
2036  !/
2050  FUNCTION cmplx_cosh(X)
2051  !/
2052  !/ +-----------------------------------+
2053  !/ | WAVEWATCH III NOAA/NCEP |
2054  !/ | Q. Liu |
2055  !/ | FORTRAN 90 |
2056  !/ | Last update : 24-Mar-2016 |
2057  !/ +-----------------------------------+
2058  !/
2059  !/ 24-Mar-2016 : Origination. ( version 5.10 )
2060  !/ ( Q. Liu )
2061  !/
2062  ! 1. Purpose :
2063  !
2064  ! For a number of compilers, the built-in function sinh, cosh and
2065  ! tanh do not support the complex inputs. So here I write an
2066  ! external one.
2067  !
2068  ! 2. Method :
2069  !
2070  ! cosh(x) = (e**x + e**(-x)) / 2 (The built in function exp supports
2071  ! complex input)
2072  !
2073  ! 3. Parameters :
2074  !
2075  ! Parameter list
2076  ! ----------------------------------------------------------------
2077  ! Name Type Intent Description
2078  ! ----------------------------------------------------------------
2079  ! X CMPL(D) I a double-precision complex var.
2080  ! ----------------------------------------------------------------
2081  ! * Note, this subr. will be only called by NR_CORR,
2082  ! so for simplicity, I only use double-precision complex var.
2083  ! as input.
2084  !
2085  ! 4. Subroutines used :
2086  !
2087  ! Name Type Module Description
2088  ! ----------------------------------------------------------------
2089  ! STRACE Subr. W3SERVMD Subroutine tracing.
2090  ! ----------------------------------------------------------------
2091  !
2092  ! 5. Called by :
2093  !
2094  ! Name Type Module Description
2095  ! ----------------------------------------------------------------
2096  ! NR_CORR Subr. / Newton-Raphson correction term.
2097  ! ----------------------------------------------------------------
2098  !
2099  ! 6. Error messages :
2100  !
2101  ! None.
2102  !
2103  ! 7. Remarks :
2104  !
2105  ! 8. Structure :
2106  !
2107  ! See source code.
2108  !
2109  ! 9. Switches :
2110  !
2111  ! !/S Enable subroutine tracing.
2112  !
2113  ! 10. Source code :
2114  !
2115  !/ ------------------------------------------------------------------- /
2116 #ifdef W3_S
2117  USE w3servmd, ONLY: strace
2118 #endif
2119  !/
2120  IMPLICIT NONE
2121  !/
2122  !/ ------------------------------------------------------------------- /
2123  !/ Parameter list
2124  !/
2125  COMPLEX(KDPC), INTENT(IN) :: x
2126  COMPLEX(KDPC) :: cmplx_cosh
2127  !/
2128  !/ ------------------------------------------------------------------- /
2129  !/ Local parameters
2130  !/
2131 #ifdef W3_S
2132  INTEGER, SAVE :: ient = 0
2133 #endif
2134  !/
2135  !/ ------------------------------------------------------------------- /
2136 #ifdef W3_S
2137  CALL strace (ient, 'CMPLX_COSH')
2138 #endif
2139  !/
2140  cmplx_cosh = (exp(x) + exp(-x)) * 0.5
2141  !/
2142  !/ End of CMPLX_COSH ------------------------------------------------- /
2143  !/
2144  END FUNCTION cmplx_cosh
2145  !/ ------------------------------------------------------------------- /
2146  !/
2160  FUNCTION cmplx_tanh2(X)
2161  !/
2162  !/ +-----------------------------------+
2163  !/ | WAVEWATCH III NOAA/NCEP |
2164  !/ | Q. Liu |
2165  !/ | FORTRAN 90 |
2166  !/ | Last update : 24-Mar-2016 |
2167  !/ +-----------------------------------+
2168  !/
2169  !/ 24-Mar-2016 : Origination. ( version 5.10 )
2170  !/ ( Q. Liu )
2171  !/
2172  ! 1. Purpose :
2173  ! We may encounter overflow error for the above tanh function as kh
2174  ! becomes huge. This is another version of tanh function
2175  !
2176  ! 2. Method :
2177  !
2178  ! See https://en.wikipedia.org/wiki/Hyperbolic_function
2179  ! tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
2180  ! = (1 - exp(-2x)) / (1 + exp(-2x))
2181  !
2182  ! 3. Parameters :
2183  !
2184  ! Parameter list
2185  ! ----------------------------------------------------------------
2186  ! Name Type Intent Description
2187  ! ----------------------------------------------------------------
2188  ! X CMPL(D) I a double-precision complex var.
2189  ! ----------------------------------------------------------------
2190  ! * Note, this subr. will be only called by NR_CORR, so for
2191  ! simplicity, I only use double-precision complex var. as input.
2192  !
2193  ! 4. Subroutines used :
2194 
2195  ! Name Type Module Description
2196  ! ----------------------------------------------------------------
2197  ! STRACE Subr. W3SERVMD Subroutine tracing.
2198  ! CMPLX_SINH Func. / sinh for complex var.
2199  ! CMPLX_COSH Func. / cosh for complex var.
2200  ! ----------------------------------------------------------------
2201  !
2202  ! 5. Called by :
2203  !
2204  ! Name Type Module Description
2205  ! ----------------------------------------------------------------
2206  ! NR_CORR Subr. / Newton-Raphson correction term.
2207  ! ----------------------------------------------------------------
2208  !
2209  ! 6. Error messages :
2210  !
2211  ! None.
2212  !
2213  ! 7. Remarks :
2214  ! Calculating tanh in this way may have problems when x ->
2215  ! -inf. But in our cases x is alway >0.
2216  !
2217  ! 8. Structure :
2218  !
2219  ! See source code.
2220  !
2221  ! 9. Switches :
2222  !
2223  ! !/S Enable subroutine tracing.
2224  !
2225  ! 10. Source code :
2226  !
2227  !/ ------------------------------------------------------------------- /
2228 #ifdef W3_S
2229  USE w3servmd, ONLY: strace
2230 #endif
2231  !/
2232  IMPLICIT NONE
2233  !/
2234  !/ ------------------------------------------------------------------- /
2235  !/ Parameter list
2236  !/
2237  COMPLEX(KDPC), INTENT(IN) :: x
2238  COMPLEX(KDPC) :: cmplx_tanh2
2239  !/
2240  !/ ------------------------------------------------------------------- /
2241  !/ Local parameters
2242  !/
2243 #ifdef W3_S
2244  INTEGER, SAVE :: ient = 0
2245 #endif
2246  !/
2247  !/ ------------------------------------------------------------------- /
2248 #ifdef W3_S
2249  CALL strace (ient, 'CMPLX_TANH2')
2250 #endif
2251  !/
2252  cmplx_tanh2 = (1 - exp(-2*x)) / (1 + exp(-2*x))
2253  !/
2254  !/ End of CMPLX_TANH2 ------------------------------------------------ /
2255  !/
2256  END FUNCTION cmplx_tanh2
2257  !/
2258  !/ ------------------------------------------------------------------- /
2259  !/
2266  SUBROUTINE init_random_seed()
2267  !/
2268  !/ +-----------------------------------+
2269  !/ | WAVEWATCH III NOAA/NCEP |
2270  !/ | Q. Liu |
2271  !/ | FORTRAN 90 |
2272  !/ | Last update : 24-Mar-2016 |
2273  !/ +-----------------------------------+
2274  !/
2275  !/ 24-Mar-2016 : Origination. ( version 5.10 )
2276  !/ ( Q. Liu )
2277  !/ 24-Mar-2016 : Borrowed from Fortran Wiki ( Q. Liu )
2278  !
2279  ! 1. Purpose :
2280  !
2281  ! Initialize the random seed based on the system's time.
2282  !
2283  ! 2. Method :
2284  !
2285  ! See http://fortranwiki.org/fortran/show/random_seed
2286  !
2287  ! 3. Parameters :
2288  !
2289  ! 4. Subroutines used :
2290  !
2291  ! 5. Called by :
2292  !
2293  ! Name Type Module Description
2294  ! ----------------------------------------------------------------
2295  ! NR_ROOT Func. / Newton-Raphson root finding.
2296  ! ----------------------------------------------------------------
2297  !
2298  ! 6. Error messages :
2299  !
2300  ! None.
2301  !
2302  ! 7. Remarks :
2303  !
2304  ! 8. Structure :
2305  !
2306  ! See source code.
2307  !
2308  ! 9. Switches :
2309  !
2310  ! !/S Enable subroutine tracing.
2311  !
2312  ! 10. Source code :
2313  !
2314  !/ ------------------------------------------------------------------- /
2315 #ifdef W3_S
2316  USE w3servmd, ONLY: strace
2317 #endif
2318  !/
2319  IMPLICIT NONE
2320  !/
2321  !/ ------------------------------------------------------------------- /
2322  !/ Local parameters
2323  !/
2324 #ifdef W3_S
2325  INTEGER, SAVE :: ient = 0
2326 #endif
2327  !/
2328  INTEGER :: i, n, clock
2329  INTEGER, DIMENSION(:), ALLOCATABLE :: seed
2330  !/ ------------------------------------------------------------------- /
2331 #ifdef W3_S
2332  CALL strace (ient, 'INIT_RANDOM_SEED')
2333 #endif
2334  !/
2335  CALL random_seed(SIZE = n)
2336  ALLOCATE(seed(n))
2337  !
2338  CALL system_clock(count=clock)
2339  !
2340  seed = clock + 37 * (/ (i - 1, i = 1, n) /)
2341  CALL random_seed(put = seed)
2342  !
2343  DEALLOCATE(seed)
2344  !/
2345  !/ End of INIT_RANDOM_SEED ------------------------------------------- /
2346  !/
2347  END SUBROUTINE init_random_seed
2348  !/
2349  !/ ------------------------------------------------------------------- /
2350  !/
2351  !/ End of module W3SIC5MD -------------------------------------------- /
2352  !/
2353 END MODULE w3sic5md
2354 !/ ------------------------------------------------------------------- /
w3gdatmd::nk
integer, pointer nk
Definition: w3gdatmd.F90:1230
w3gdatmd::nspec
integer, pointer nspec
Definition: w3gdatmd.F90:1230
w3idatmd::inflags2
logical, dimension(:), pointer inflags2
Definition: w3idatmd.F90:260
w3gsrumd
Definition: w3gsrumd.F90:17
w3gdatmd::sig
real, dimension(:), pointer sig
Definition: w3gdatmd.F90:1234
w3gdatmd::ic5pars
real, dimension(:), pointer ic5pars
Definition: w3gdatmd.F90:1158
w3odatmd::iaproc
integer, pointer iaproc
Definition: w3odatmd.F90:457
w3arrymd::outmat
subroutine outmat(NDS, A, MX, NX, NY, MNAME)
Definition: w3arrymd.F90:988
w3odatmd::ndse
integer, pointer ndse
Definition: w3odatmd.F90:456
w3odatmd::naperr
integer, pointer naperr
Definition: w3odatmd.F90:457
w3servmd
Definition: w3servmd.F90:3
w3gdatmd::nth
integer, pointer nth
Definition: w3gdatmd.F90:1230
w3odatmd
Definition: w3odatmd.F90:3
w3odatmd::naproc
integer, pointer naproc
Definition: w3odatmd.F90:457
w3sic5md::w3sic5
subroutine, public w3sic5(A, DEPTH, CG, WN, IX, IY, S, D)
Calculate ice source term S_{ice} according to 3 different sea ice models.
Definition: w3sic5md.F90:169
constants::tpi
real, parameter tpi
TPI 2*Pi.
Definition: constants.F90:72
w3servmd::strace
subroutine strace(IENT, SNAME)
Definition: w3servmd.F90:148
w3idatmd
Define data structures to set up wave model input data for several models simultaneously.
Definition: w3idatmd.F90:16
w3gdatmd::mapwn
integer, dimension(:), pointer mapwn
Definition: w3gdatmd.F90:1231
w3arrymd
Definition: w3arrymd.F90:3
w3odatmd::ndst
integer, pointer ndst
Definition: w3odatmd.F90:456
constants
Define some much-used constants for global use (all defined as PARAMETER).
Definition: constants.F90:20
w3gdatmd
Definition: w3gdatmd.F90:16
w3dispmd::wavnu1
subroutine wavnu1(SI, H, K, CG)
Definition: w3dispmd.F90:85
w3sic5md::fsdisp
subroutine, public fsdisp(HICE, IVISC, RHOI, ISMODG, HWAT, WT, WNR, WNI)
Calculate the complex wavenumber for waves in ice according to three different sea ice models.
Definition: w3sic5md.F90:653
w3servmd::extcde
subroutine extcde(IEXIT, UNIT, MSG, FILE, LINE, COMM)
Definition: w3servmd.F90:736
w3arrymd::prt2ds
subroutine prt2ds(NDS, NFR0, NFR, NTH, E, FR, UFR, FACSP, FSC, RRCUT, PRVAR, PRUNIT, PNTNME)
Definition: w3arrymd.F90:1943
w3sic5md::w3ic5wncg
subroutine, public w3ic5wncg(WN_R, WN_I, CG, HICE, IVISC, RHOI, ISMODG, HWAT)
Calculation of complex wavenumber arrays for ice-coupled waves.
Definition: w3sic5md.F90:495
w3dispmd
Definition: w3dispmd.F90:3
constants::grav
real, parameter grav
GRAV Acc.
Definition: constants.F90:61
w3sic5md
Calculate ice source term S_{ice} according to different ice models:
Definition: w3sic5md.F90:25