WAVEWATCH III  beta 0.0.1
w3servmd.F90
Go to the documentation of this file.
1 #include "w3macros.h"
2 !/ ------------------------------------------------------------------- /
3 MODULE w3servmd
4  !/
5  !/ +-----------------------------------+
6  !/ | WAVEWATCH III NOAA/NCEP |
7  !/ | H. L. Tolman |
8  !/ | FORTRAN 90 |
9  !/ | Last update : 15-Jan-2021 |
10  !/ +-----------------------------------+
11  !/
12  !/ For update log see individual subroutines.
13  !/ 12-Jun-2012 : Add /RTD option or rotated grid option.
14  !/ (Jian-Guo Li) ( version 4.06 )
15  !/ 11-Nov-2013 : SMC and rotated grid incorporated in the main
16  !/ trunk ( version 4.13 )
17  !/ 18-Aug-2016 : Add dist_sphere: angular distance ( version 5.11 )
18  !/ 01-Mar-2016 : Added W3THRTN and W3XYRTN for post ( version 6.02 )
19  !/ processing rotated grid data
20  !/ 15-Jan-2021 : Added UV_TO_MAG_DIR routine ( version 7.12 )
21  !/
22  !/ Copyright 2009-2012 National Weather Service (NWS),
23  !/ National Oceanic and Atmospheric Administration. All rights
24  !/ reserved. WAVEWATCH III is a trademark of the NWS.
25  !/ No unauthorized use without permission.
26  !/
27  ! 1. Purpose :
28  !
29  ! In this module all WAVEWATCH specific service routines have
30  ! been gathered.
31  !
32  ! 2. Variables and types :
33  !
34  ! Name Type Scope Description
35  ! ----------------------------------------------------------------
36  ! NDSTRC Int. Private Data set number for output of STRACE
37  ! (set in ITRACE).
38  ! NTRACE Int. Private Maximum number of trace prints in
39  ! strace (set in ITRACE).
40  ! ----------------------------------------------------------------
41  !
42  ! 3. Subroutines and functions :
43  !
44  ! Name Type Scope Description
45  ! ----------------------------------------------------------------
46  ! ITRACE Subr. Public (Re-) Initialization for STRACE.
47  ! STRACE Subr. Public Enable subroutine tracing, usually
48  ! activated with the !/S switch.
49  ! NEXTLN Subr. Public Get to next line in input command file.
50  ! W3S2XY Subr. Public Grid conversion routine.
51  ! EJ5P R.F. Public Five parameter JONSWAP spectrum.
52  ! WWDATE Subr. Public Get system date.
53  ! WWTIME Subr. Public Get system time.
54  ! EXTCDE Subr. Public Abort program with exit code.
55  ! Four subs for rotated grid are appended to this module. As they
56  ! are shared with SMC grid, they are not quoted by option /RTD but
57  ! are available for general use. JGLi12Jun2012
58  ! W3SPECTN turns wave spectrum anti-clockwise by AnglD
59  ! W3ACTURN turns wave action(k,nth) anti-clockwise by AnglD.
60  ! W3LLTOEQ convert standard into rotated lat/lon, plus AnglD
61  ! W3EQTOLL revers of the LLTOEQ, but AnglD unchanged.
62  ! W3THTRN turns direction value anti-clockwise by AnglD
63  ! W3XYTRN turns 2D vectors anti-clockwise by AnglD
64  !
65  ! ----------------------------------------------------------------
66  !
67  ! 4. Subroutines and functions used :
68  !
69  ! None.
70  !
71  ! 5. Remarks :
72  !
73  ! 6. Switches
74  !
75  ! !/S Enable subroutine tracing using STRACE in this module.
76  !
77  ! 7. Source code :
78  !
79  !/ ------------------------------------------------------------------- /
80 
81  ! module default
82  implicit none
83 
84  PUBLIC
85  !
86  INTEGER, PRIVATE :: NDSTRC = 6, ntrace = 0
87  !
88 CONTAINS
89  !/ ------------------------------------------------------------------- /
90  SUBROUTINE itrace (NDS, NMAX)
91  !/
92  !/ +-----------------------------------+
93  !/ | WAVEWATCH III NOAA/NCEP |
94  !/ | H. L. Tolman |
95  !/ | FORTRAN 90 |
96  !/ | Last update : 23-Nov-1999 |
97  !/ +-----------------------------------+
98  !/
99  !/ 23-Nov-1999 : First version of routine. ( version 2.00 )
100  !/
101  ! 1. Purpose :
102  !
103  ! (Re-) initialization for module version of STRACE.
104  !
105  ! 3. Parameter list
106  ! ----------------------------------------------------------------
107  ! NDS Int. I Data set number ofr trace file.
108  ! NMAX Int. I Maximum number of traces per routine.
109  ! ----------------------------------------------------------------
110  !
111  ! Private to module :
112  ! ----------------------------------------------------------------
113  ! NDSTRC Int. Output unit number for trace. ( from NDS )
114  ! NTRACE Int. Maximum number of trace prints. ( from NMAX )
115  ! ----------------------------------------------------------------
116  !
117  ! 4. Subroutines used :
118  !
119  ! None.
120  !
121  ! 5. Called by :
122  !
123  ! Any program, multiple calls allowed.
124  !
125  ! 9. Switches :
126  !
127  ! 10. Source code :
128  !
129  !/ ------------------------------------------------------------------- /
130  !/
131  !/ ------------------------------------------------------------------- /
132  !/ Parameter list
133  !/
134  INTEGER, INTENT(IN) :: NDS, NMAX
135  !/
136  !/ ------------------------------------------------------------------- /
137  !/
138  ntrace = max( 0 , nmax )
139  ndstrc = nds
140  !
141  RETURN
142  !/
143  !/ End of ITRACE ----------------------------------------------------- /
144  !/
145  END SUBROUTINE itrace
146  !/ ------------------------------------------------------------------- /
147  SUBROUTINE strace (IENT, SNAME)
148  !/
149  !/ +-----------------------------------+
150  !/ | WAVEWATCH III NOAA/NCEP |
151  !/ | H. L. Tolman |
152  !/ | FORTRAN 90 |
153  !/ | Last update : 25-Jan-2000 |
154  !/ +-----------------------------------+
155  !/ Original version by N. Booij, DUT
156  !/
157  !/ 30-Mar-1993 : Final FORTRAN 77 ( version 1.18 )
158  !/ 23-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
159  !/ 25-Jan-2000 : Force flushing of uniit. ( version 2.00 )
160  !/ This was taken out around version 3.01.
161  !/
162  ! 1. Purpose :
163  !
164  ! Keep track of entered subroutines.
165  !
166  ! 3. Parameter list
167  ! ----------------------------------------------------------------
168  ! IENT Int. I/O Number of times that STRACE has been
169  ! called by the routine.
170  ! SNAME Char. I Name of the subroutine (max. 6 characters)
171  ! ----------------------------------------------------------------
172  !
173  ! Private to module :
174  ! ----------------------------------------------------------------
175  ! NDSTRC Int. Output unit number for trace.
176  ! NTRACE Int. Maximum number of trace prints.
177  ! ----------------------------------------------------------------
178  !
179  ! 4. Subroutines used :
180  !
181  ! None.
182  !
183  ! 5. Called by :
184  !
185  ! Any program, after private variables have been set by NTRACE.
186  !
187  ! 9. Switches :
188  !
189  ! 10. Source code :
190  !
191  !/ ------------------------------------------------------------------- /
192  !/
193  !/ ------------------------------------------------------------------- /
194  !/ Parameter list
195  !/
196  INTEGER, INTENT(INOUT) :: IENT
197  CHARACTER, INTENT(IN) :: SNAME*(*)
198  !/
199  !/ ------------------------------------------------------------------- /
200  !/
201  IF (ntrace.EQ.0 .OR. ient.GE.ntrace) RETURN
202  !
203  ient = ient + 1
204  IF (ient.EQ.1) THEN
205  WRITE (ndstrc,10) sname
206  ELSE
207  WRITE (ndstrc,11) sname, ient
208  END IF
209  !
210  RETURN
211  !
212  ! Formats
213  !
214 10 FORMAT (' ---> TRACE SUBR : ',a6)
215 11 FORMAT (' ---> TRACE SUBR : ',a6,' ENTRY: ',i6)
216  !/
217  !/ End of STRACE ----------------------------------------------------- /
218  !/
219  END SUBROUTINE strace
220  !/ ------------------------------------------------------------------- /
221  SUBROUTINE nextln ( CHCKC , NDSI , NDSE )
222  !/
223  !/ +-----------------------------------+
224  !/ | WAVEWATCH III NOAA/NCEP |
225  !/ | H. L. Tolman |
226  !/ | FORTRAN 90 |
227  !/ | Last update : 10-Dec-2014 |
228  !/ +-----------------------------------+
229  !/
230  !/ 15-Jan-1999 : Final FORTRAN 77 ( version 1.18 )
231  !/ 18-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
232  !/ 10-Dec-2014 : Skip blank lines and leading blanks ( version 5.04 )
233  !/
234  ! 1. Purpose :
235  !
236  ! Sets file pointer to next active line of input file, by skipping
237  ! blank lines and lines starting with the character CHCKC. Leading
238  ! white space is allowed before the character CHCKC.
239  !
240  ! 3. Parameters :
241  !
242  ! Parameter list
243  ! ----------------------------------------------------------------
244  ! CHCKC C*1 I Check character for defining comment line.
245  ! NDSI Int. I Input dataset number.
246  ! NDSE Int. I Error output dataset number.
247  ! (No output if NDSE < 0).
248  ! ----------------------------------------------------------------
249  !
250  ! 4. Subroutines used :
251  !
252  ! STRACE ( !/S switch )
253  !
254  ! 5. Called by :
255  !
256  ! Any routine.
257  !
258  ! 6. Error messages :
259  !
260  ! - On EOF or error in input file.
261  !
262  ! 9. Switches :
263  !
264  ! !/S Enable subroutine tracing.
265  !
266  ! 10. Source code :
267  !
268  !/ ------------------------------------------------------------------- /
269  !/
270  !/ ------------------------------------------------------------------- /
271  !/ Parameter list
272  !/
273  INTEGER, INTENT(IN) :: NDSI, NDSE
274  CHARACTER, INTENT(IN) :: CHCKC*1
275  !/
276  !/ ------------------------------------------------------------------- /
277  !/ Local parameters
278  !/
279 #ifdef W3_S
280  INTEGER, SAVE :: IENT = 0
281 #endif
282  INTEGER :: IERR
283  CHARACTER(128) :: MSG
284  CHARACTER(256) :: LINE, TEST
285  !/
286  !/ ------------------------------------------------------------------- /
287  !/
288 #ifdef W3_S
289  CALL strace (ient, 'NEXTLN')
290 #endif
291  !
292 100 CONTINUE
293  ! read line
294  READ ( ndsi, 900, END=800, ERR=801, IOSTAT=IERR, IOMSG=MSG ) line
295  ! leading blanks removed and placed on the right
296  test = adjustl( line )
297  IF ( test(1:1).EQ.chckc .OR. len_trim(test).EQ.0 ) THEN
298  ! if comment or blank line, then skip
299  GOTO 100
300  ELSE
301  ! otherwise, backup to beginning of line
302  backspace( ndsi, err=802, iostat=ierr, iomsg=msg )
303  ENDIF
304  RETURN
305  !
306 800 CONTINUE
307  IF ( ndse .GE. 0 ) WRITE (ndse,910)
308  CALL extcde ( 1 )
309  !
310 801 CONTINUE
311  IF ( ndse .GE. 0 ) WRITE (ndse,911) ierr, trim(msg)
312  CALL extcde ( 2 )
313  !
314 802 CONTINUE
315  IF ( ndse .GE. 0 ) WRITE (ndse,912) ierr, trim(msg)
316  CALL extcde ( 3 )
317  !
318  ! Formats
319  !
320 900 FORMAT (a)
321 910 FORMAT (/' *** WAVEWATCH III ERROR IN NEXTLN : '/ &
322  ' PREMATURE END OF INPUT FILE'/)
323 911 FORMAT (/' *** WAVEWATCH III ERROR IN NEXTLN : '/ &
324  ' ERROR IN READING FROM FILE'/ &
325  ' IOSTAT =',i5,/ &
326  ' IOMSG = ',a/)
327 912 FORMAT (/' *** WAVEWATCH III ERROR IN NEXTLN : '/ &
328  ' ERROR ON BACKSPACE'/ &
329  ' IOSTAT =',i5,/ &
330  ' IOMSG = ',a/)
331  !/
332  !/ End of NEXTLN ----------------------------------------------------- /
333  !/
334  END SUBROUTINE nextln
335  !/ ------------------------------------------------------------------- /
336  SUBROUTINE w3s2xy ( NSEA, MSEA, MX, MY, S, MAPSF, XY )
337  !/
338  !/ +-----------------------------------+
339  !/ | WAVEWATCH III NOAA/NMC |
340  !/ | H. L. Tolman |
341  !/ | FORTRAN 90 |
342  !/ | Last update : 23-Nov-1999 |
343  !/ +-----------------------------------+
344  !/
345  !/ 11-Dec-1996 : Final FORTRAN 77 ( version 1.18 )
346  !/ 23-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
347  !/
348  ! 1. Purpose :
349  !
350  ! Convert a data array on the storage grid to a data array on the
351  ! full spatial grid. Land and ice points in the full grid are
352  ! not touched. Output array of conventional type XY(IX,IY).
353  !
354  ! 3. Parameters :
355  !
356  ! Parameter list
357  ! ----------------------------------------------------------------
358  ! NSEA Int. I Number of sea points.
359  ! MSEA, MX, MY
360  ! Int. I Array dimensions.
361  ! S R.A. I Data on storage grid.
362  ! MAPSF I.A. I Storage map for IX and IY, resp.
363  ! XY R.A. O Data on XY grid.
364  ! ----------------------------------------------------------------
365  !
366  ! 4. Subroutines used :
367  !
368  ! None.
369  !
370  ! 5. Called by :
371  !
372  ! Any WAVEWATCH III routine.
373  !
374  ! 9. Switches :
375  !
376  ! None.
377  !
378  ! 10. Source code :
379  !
380  !/ ------------------------------------------------------------------- /
381  !/
382  !/ ------------------------------------------------------------------- /
383  !/ Parameter list
384  !/
385  INTEGER, INTENT(IN) :: MSEA, NSEA, MX, MY, MAPSF(MSEA,2)
386  REAL, INTENT(IN) :: S(MSEA)
387  REAL, INTENT(OUT) :: XY(MX,MY)
388  !/
389  !/ ------------------------------------------------------------------- /
390  !/ Local parameters
391  !/
392  INTEGER :: ISEA, IX, IY
393  !/
394  !/ ------------------------------------------------------------------- /
395  !/
396  DO isea=1, nsea
397  ix = mapsf(isea,1)
398  iy = mapsf(isea,2)
399  xy(ix,iy) = s(isea)
400  end do
401  !/
402  !/ End of W3S2XY ----------------------------------------------------- /
403  !/
404  END SUBROUTINE w3s2xy
405  !/ ------------------------------------------------------------------- /
406  REAL FUNCTION EJ5P ( F, ALFA, FP, YLN, SIGA, SIGB )
407  !/
408  !/ +-----------------------------------+
409  !/ | WAVEWATCH III NOAA/NCEP |
410  !/ | H. L. Tolman |
411  !/ | FORTRAN 90 |
412  !/ | Last update : 23-Nov-1999 |
413  !/ +-----------------------------------+
414  !/
415  !/ 23-AMy-1985 : Original by G. Ph. van Vledder.
416  !/ 23-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
417  !/
418  ! 1. Purpose :
419  !
420  ! Computation of spectral density using a 5-parameter
421  ! JONSWAP-spectrum
422  !
423  ! 2. Method
424  !
425  ! EJ5P(F) = A.EXP(B + LN(Y).EXP(C))
426  !
427  ! where: A = ALFA * 0.06175 * F**(-5)
428  ! B = -1.25*(FP/F)**4
429  ! C = -0.5 * ((F - FP)/(SIG * FP))**2
430  ! and
431  ! GRAV**2/(2.PI)**4 = 0.06175
432  !
433  ! 3. Parameters :
434  !
435  ! Parameter list
436  !
437  ! ----------------------------------------------------------------
438  ! F Real I Frequency in Hz
439  ! ALFA Real I Energy scaling factor
440  ! FP Real I Peak frequency in Hz
441  ! YLN Real I Peak overshoot factor, given by LN-value
442  ! SIGA Real I Spectral width, for F < FP
443  ! SIGB Real I Spectral width, FOR F > FP
444  ! ----------------------------------------------------------------
445  !
446  ! 4. Subroutines used :
447  !
448  ! None.
449  !
450  ! 5. Called by :
451  !
452  ! Any.
453  !
454  ! 6. Error messages :
455  !
456  ! 7. Remarks :
457  !
458  ! EXPMIN is a machine dependant constant such that
459  ! EXP(EXPMIN) can be successfully evaluated without
460  ! underflow by the compiler supllied EXP routine.
461  !
462  ! 8. Structure :
463  !
464  ! See source code.
465  !
466  ! 9. Switches :
467  !
468  ! None.
469  !
470  ! 10. Source code :
471  !
472  !/ ------------------------------------------------------------------- /
473  !/
474  !/ ------------------------------------------------------------------- /
475  !/ Parameter list
476  !/
477  REAL, INTENT(IN) :: f, alfa, fp, yln, siga, sigb
478  !/
479  !/ ------------------------------------------------------------------- /
480  !/ Local parameters
481  !/
482  REAL :: sig, a, b, c
483  REAL, SAVE :: eps=1.e-4, expmin=-180.
484  !/
485  !/ ------------------------------------------------------------------- /
486  !/
487  IF(f.LT.eps) THEN
488  ej5p = 0.0
489  RETURN
490  END IF
491  !
492  a = alfa * 0.06175 / f**5
493  b = -1.25 * (fp/f)**4
494  b = max(b,expmin)
495  !
496  IF (yln.LT.eps) THEN
497  ej5p = a * exp(b)
498  ELSE
499  IF( f.LE.fp) THEN
500  sig = siga
501  ELSE
502  sig = sigb
503  END IF
504  c = -0.5 * ((f - fp)/(sig * fp))**2
505  c = max(c,expmin)
506  ej5p = a * exp(b + exp(c) * yln)
507  END IF
508  !
509  RETURN
510  !/
511  !/ End of NEXTLN ----------------------------------------------------- /
512  !/
513  END FUNCTION ej5p
514  !/ ------------------------------------------------------------------- /
515  REAL function dist_sphere ( lo1,la1,lo2,la2 )
516  !/
517  !/ +-----------------------------------+
518  !/ | WAVEWATCH III NOAA/NCEP |
519  !/ | F. Ardhuin |
520  !/ | FORTRAN 90 |
521  !/ | Last update : 18-Aug-2016 |
522  !/ +-----------------------------------+
523  !/
524  !/ 18-Aug-2016 : Creation ( version 5.11 )
525  !/
526  ! 1. Purpose :
527  !
528  ! Computes distance between two points on a sphere
529  !
530  ! 2. Method
531  !
532  !
533  ! 3. Parameters :
534  !
535  ! Parameter list
536  !
537  ! ----------------------------------------------------------------
538  ! LO1 Real I Longitude of 1st point
539  ! LA1 Real I Latitude of 1st point
540  ! LO2 Real I Longitude of 2nd point
541  ! LA2 Real I Latitude of 2nd point
542  ! ----------------------------------------------------------------
543  !
544  ! 4. Subroutines used :
545  !
546  ! None.
547  !
548  ! 5. Called by :
549  !
550  ! WW3_BOUNC
551  !
552  ! 6. Error messages :
553  !
554  ! 7. Remarks :
555  !
556  ! None.
557  !
558  ! 8. Structure :
559  !
560  ! See source code.
561  !
562  ! 9. Switches :
563  !
564  ! None.
565  !
566  ! 10. Source code :
567  !
568  !/ ------------------------------------------------------------------- /
569  USE constants
570  !/
571  !/ ------------------------------------------------------------------- /
572  !/ Parameter list
573  !/
574  REAL, INTENT(IN) :: lo1, la1, lo2, la2
575  !/
576  !/ ------------------------------------------------------------------- /
577  !/ Local parameters
578  !/
579  ! None
580  !/
581  !/ ------------------------------------------------------------------- /
582  !/
583  dist_sphere=acos(sin(la2*dera)*sin(la1*dera)+ &
584  cos(la2*dera)*cos(la1*dera)*cos((lo2-lo1)*dera))*rade
585  !
586  RETURN
587  !/
588  !/ End of NEXTLN ----------------------------------------------------- /
589  !/
590  END FUNCTION dist_sphere
591  !/ ------------------------------------------------------------------- /
592 
593  !/ ------------------------------------------------------------------- /
594  SUBROUTINE wwdate (STRNG)
595  !/
596  !/ +-----------------------------------+
597  !/ | WAVEWATCH III NOAA/NCEP |
598  !/ | H. L. Tolman |
599  !/ | FORTRAN 90 |
600  !/ | Last update : 26-Dec-2012 |
601  !/ +-----------------------------------+
602  !/
603  !/ 23-Dec-1998 : Final FORTRAN 77 ( version 1.18 )
604  !/ 23-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
605  !/ 18-Sep-2000 : PGI switch added ( version 2.04 )
606  !/ 13-Mar-2001 : LF95 switch added ( version 2.09 )
607  !/ 08-May-2002 : Replace obsolete switches with F90 ( version 2.21 )
608  !/ 26-Dec-2012 : Modified obsolete declarations. ( version 4.11 )
609  !/
610  ! 1. Purpose :
611  !
612  ! Get date from machine dependent routine.
613  !
614  ! 3. Parameters :
615  !
616  ! Parameter list
617  ! ----------------------------------------------------------------
618  ! STRNG C*10 O String with date in format YYYY/MM/DD
619  ! ----------------------------------------------------------------
620  !
621  ! 4. Subroutines used :
622  !
623  ! Machine dependent.
624  !
625  ! 5. Called by :
626  !
627  ! Any routine.
628  !
629  ! 9. Switches :
630  !
631  ! 10. Source code :
632  !
633  !/ ------------------------------------------------------------------- /
634  !/
635  !/ ------------------------------------------------------------------- /
636  !/ Parameter list
637  !/
638  CHARACTER, INTENT(OUT) :: STRNG*10
639  !/
640  !/ ------------------------------------------------------------------- /
641  !/ Local parameters
642  !/
643  CHARACTER(LEN=8) :: DATE
644  CHARACTER(LEN=10) :: TIME
645  CHARACTER(LEN=5) :: ZONE
646  INTEGER :: VALUES(8)
647  !/
648  !/ ------------------------------------------------------------------- /
649  !/
650  strng = '----/--/--'
651  CALL date_and_time ( date, time, zone, values )
652  strng(1:4) = date(1:4)
653  strng(6:7) = date(5:6)
654  strng(9:10) = date(7:8)
655  !
656  !
657  RETURN
658  !/
659  !/ End of WWDATE ----------------------------------------------------- /
660  !/
661  END SUBROUTINE wwdate
662  !/ ------------------------------------------------------------------- /
663  SUBROUTINE wwtime (STRNG)
664  !/
665  !/ +-----------------------------------+
666  !/ | WAVEWATCH III NOAA/NCEP |
667  !/ | H. L. Tolman |
668  !/ | FORTRAN 90 |
669  !/ | Last update : 26-Dec-2012 |
670  !/ +-----------------------------------+
671  !/
672  !/ 23-Dec-1998 : Final FORTRAN 77 ( version 1.18 )
673  !/ 23-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
674  !/ 18-Sep-2000 : PGI switch added ( version 2.04 )
675  !/ 13-Mar-2001 : LF95 switch added ( version 2.09 )
676  !/ 08-May-2002 : Replace obsolete switches with F90 ( version 2.21 )
677  !/ 26-Dec-2012 : Modified obsolete declarations. ( version 4.11 )
678  !/
679  ! 1. Purpose :
680  !
681  ! Get time from machine dependent routine.
682  !
683  ! 2. Method :
684  !
685  !
686  ! 3. Parameters :
687  !
688  ! Parameter list
689  ! ----------------------------------------------------------------
690  ! STRNG C*8 O String with time in format hh:mm:ss
691  ! ----------------------------------------------------------------
692  !
693  ! 4. Subroutines used :
694  !
695  ! Machine dependent.
696  !
697  ! 5. Called by :
698  !
699  ! Any routine.
700  !
701  ! 9. Switches :
702  !
703  ! 10. Source code :
704  !
705  !/ ------------------------------------------------------------------- /
706  !/
707  !/ ------------------------------------------------------------------- /
708  !/ Parameter list
709  !/
710  CHARACTER, INTENT(OUT) :: STRNG*8
711  !/
712  !/ ------------------------------------------------------------------- /
713  !/ Local parameters
714  !/
715  CHARACTER(LEN=8) :: DATE
716  CHARACTER(LEN=10) :: TIME
717  CHARACTER(LEN=5) :: ZONE
718  INTEGER :: VALUES(8)
719  !/
720  !/ ------------------------------------------------------------------- /
721  !/
722  !
723  strng = '--:--:--'
724  CALL date_and_time ( date, time, zone, values )
725  strng(1:2) = time(1:2)
726  strng(4:5) = time(3:4)
727  strng(7:8) = time(5:6)
728  !
729  RETURN
730  !/
731  !/ End of WWTIME ----------------------------------------------------- /
732  !/
733  END SUBROUTINE wwtime
734  !/ ------------------------------------------------------------------- /
735  SUBROUTINE extcde ( IEXIT, UNIT, MSG, FILE, LINE, COMM )
736  !/
737  !/ +-----------------------------------+
738  !/ | WAVEWATCH III NOAA/NCEP |
739  !/ | H. L. Tolman |
740  !/ | FORTRAN 90 |
741  !/ | Last update : 06-Jun-2018 |
742  !/ +-----------------------------------+
743  !/
744  !/ 06-Jan-1998 : Final FORTRAN 77 ( version 1.18 )
745  !/ 23-Nov-1999 : Upgrade to FORTRAN 90 ( version 2.00 )
746  !/ 10-Dec-2014 : Add checks for allocate status ( version 5.04 )
747  !/ 11-Mar-2015 : Allow non-error exit (iexit=0) ( version 5.04 )
748  !/ 20-Jan-2017 : Add optional MPI communicator arg ( version 6.02 )
749  !/ 06-Jun-2018 : Add optional MPI ( version 6.04 )
750  !/
751  ! 1. Purpose :
752  !
753  ! Perform a program stop with an exit code.
754  !
755  ! If exit code IEXIT=0, then it is not an error, but
756  ! a stop has been requested by the calling routine:
757  ! wait for other processes in communicator to catch up.
758  !
759  ! If exit code IEXIT.ne.0, then abort program w/out
760  ! waiting for other processes to catch up (important for example
761  ! when not all processes are used by WW3).
762  !
763  ! 2. Method :
764  !
765  ! Machine dependent.
766  !
767  ! 3. Parameters :
768  !
769  ! Parameter list
770  ! ----------------------------------------------------------------
771  ! IEXIT Int. I Exit code to be used.
772  ! UNIT Int. I (optional) file unit to write error message
773  ! MSG Str. I (optional) error message
774  ! FILE Str. I (optional) name of source code file
775  ! LINE Int. I (optional) line number in source code file
776  ! COMM Int. I (optional) MPI communicator
777  ! ----------------------------------------------------------------
778  !
779  ! 4. Subroutines used :
780  !
781  ! 5. Called by :
782  !
783  ! Any.
784  !
785  ! 9. Switches :
786  !
787  ! !/MPI MPI finalize interface if active
788  !
789  ! 10. Source code :
790  !
791  !/ ------------------------------------------------------------------- /
792  !
793 #ifdef W3_MPI
794  include "mpif.h"
795 #endif
796  !/
797  !/ ------------------------------------------------------------------- /
798  !/ Parameter list
799  !/
800  INTEGER, INTENT(IN) :: IEXIT
801  INTEGER, INTENT(IN), OPTIONAL :: UNIT
802  CHARACTER(*), INTENT(IN), OPTIONAL :: MSG
803  CHARACTER(*), INTENT(IN), OPTIONAL :: FILE
804  INTEGER, INTENT(IN), OPTIONAL :: LINE
805  INTEGER, INTENT(IN), OPTIONAL :: COMM
806  !/
807  !/ ------------------------------------------------------------------- /
808  !/
809 #ifdef W3_MPI
810  INTEGER :: IERR_MPI
811  LOGICAL :: RUN
812 #endif
813  INTEGER :: IUN
814  CHARACTER(256) :: LMSG = ""
815  CHARACTER(6) :: LSTR
816  CHARACTER(10) :: PREFIX = "WW3 ERROR:"
817  !/
818  !/ Set file unit for error output
819  !/
820  iun = 0
821  IF (PRESENT(unit)) iun = unit
822  !/
823  !/ Report error message
824  !/
825  IF (PRESENT(msg)) THEN
826  WRITE (iun,"(A)") prefix//" "//trim(msg)
827  END IF
828  !/
829  !/ Report context
830  !/
831  IF ( PRESENT(file) ) THEN
832  lmsg = trim(lmsg)//" FILE="//trim(file)
833  END IF
834  IF ( PRESENT(line) ) THEN
835  WRITE (lstr,'(I0)') line
836  lmsg = trim(lmsg)//" LINE="//trim(lstr)
837  END IF
838  IF ( len_trim(lmsg).GT.0 ) THEN
839  WRITE (iun,"(A)") prefix//trim(lmsg)
840  END IF
841  !/
842  !/ Handle MPI exit
843  !/
844 #ifdef W3_MPI
845  CALL mpi_initialized ( run, ierr_mpi )
846  IF ( run ) THEN
847  IF ( iexit.EQ.0 ) THEN ! non-error state
848  IF ( PRESENT(comm) ) CALL mpi_barrier ( comm, ierr_mpi )
849  CALL mpi_finalize (ierr_mpi )
850  ELSE ! error state
851  WRITE(*,'(/A,I6/)') 'EXTCDE MPI_ABORT, IEXIT=', iexit
852  IF (PRESENT(unit)) THEN
853  WRITE(*,'(/A,I6/)') 'EXTCDE UNIT=', unit
854  END IF
855  IF (PRESENT(msg)) THEN
856  WRITE(*,'(/2A/)') 'EXTCDE MSG=', msg
857  END IF
858  IF (PRESENT(file)) THEN
859  WRITE(*,'(/2A/)') 'EXTCDE FILE=', file
860  END IF
861  IF (PRESENT(line)) THEN
862  WRITE(*,'(/A,I8/)') 'EXTCDE LINE=', line
863  END IF
864  IF (PRESENT(comm)) THEN
865  WRITE(*,'(/A,I6/)') 'EXTCDE COMM=', comm
866  END IF
867  CALL mpi_abort ( mpi_comm_world, iexit, ierr_mpi )
868  END IF
869  END IF
870 #endif
871  !/
872  !/ Handle non-MPI exit
873  !/
874  CALL exit ( iexit )
875  !/
876  !/ End of EXTCDE ----------------------------------------------------- /
877  !/
878  END SUBROUTINE extcde
879  !/ ------------------------------------------------------------------- /
880  ! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
881  ! This subroutine turn the wave spectrum by an fixed angle anti-clockwise
882  ! so that it may be used in the rotated or stanadard system.
883  ! First created: 26 Aug 2005 Jian-Guo Li
884  ! Last modified: 21 Feb 2008 Jian-Guo Li
885  !
886  ! Subroutine Interface:
887 
888  Subroutine w3spectn( NFreq, NDirc, Alpha, Spectr )
889 
890  ! Description:
891  ! Rotates wave spectrum anticlockwise by angle alpha in degree
892  ! This routine is distinct from W3ACTURN since orders spectrum as freq, dirn
893  !
894  ! Subroutine arguments
895  INTEGER, INTENT(IN) :: NFreq, NDirc ! No. freq and dirn bins
896  REAL, INTENT(IN) :: Alpha ! Turning angle (degrees)
897  REAL, INTENT(INOUT) :: Spectr(NFreq,NDirc) ! Wave spectrum in/out
898 
899  ! Local variables
900  INTEGER :: ii, jj, kk, nsft
901  REAL :: Ddirc, frac, CNST
902  REAL, Dimension(NFreq) :: Wrkfrq, Tmpfrq
903  REAL, Dimension(NFreq,NDirc):: Wrkspc
904 
905  ! Check input bin numbers
906  IF( (nfreq .LT. 0) .OR. (ndirc .LT. 0) ) THEN
907  print*, " Invalid bin number NF or ND", nfreq, ndirc
908  RETURN
909  ELSE
910  ddirc=360.0/float(ndirc)
911  ENDIF
912 
913  ! Work out shift bin number and fraction
914 
915  cnst=alpha/ddirc
916  nsft=int( cnst )
917  frac= cnst - float( nsft )
918  ! PRINT*, ' nsft and frac =', nsft, frac
919 
920  ! Shift nsft bins if >=1
921  IF( abs(nsft) .GE. 1 ) THEN
922  DO ii=1, ndirc
923 
924  ! Wave spectral direction bin number is assumed to increase Anti-clockwise from EAST
925  ! So shift nsft bins anticlockwise results in local bin number decreasing by nsft
926  jj=ii - nsft
927 
928  ! As nsft may be either positive or negative depends on alpha, wrapping may
929  ! happen in either ends of the bin number train
930  IF( jj > ndirc ) jj=jj - ndirc
931  IF( jj < 1 ) jj=jj + ndirc
932 
933  ! Copy the selected bin to the loop bin number
934  wrkspc(:,ii)=spectr(:,jj)
935 
936  ENDDO
937 
938  ! If nsft=0, no need to shift, simply copy
939  ELSE
940  wrkspc = spectr
941  ENDIF
942 
943  ! Pass fraction of wave energy in frac direction
944  ! Wave spectral direction bin number is assumed to increase Anti-clockwise from EAST
945  ! So Positive frac or anticlock case, smaller bin upstream
946  IF( frac > 0.0 ) THEN
947  tmpfrq=wrkspc(:,ndirc)*frac
948  DO kk=1, ndirc
949  wrkfrq=wrkspc(:,kk)*frac
950  spectr(:,kk)=wrkspc(:,kk) - wrkfrq + tmpfrq
951  tmpfrq=wrkfrq
952  ENDDO
953  ELSE
954  ! Negative or clockwise case, larger bin upstream
955  tmpfrq=wrkspc(:,1)*frac
956  DO kk=ndirc, 1, -1
957  wrkfrq=wrkspc(:,kk)*frac
958  spectr(:,kk)=wrkspc(:,kk) + wrkfrq - tmpfrq
959  tmpfrq=wrkfrq
960  ENDDO
961  ENDIF
962 
963  ! Spectral turning completed
964 
965  RETURN
966  END SUBROUTINE w3spectn
967  !
968  ! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
969  ! This subroutine turn the wave action by an angle (deg) anti-clockwise
970  ! so that it may be used in the rotated or stanadard system.
971  ! First created: 26 Aug 2005 Jian-Guo Li
972  ! Last modified: 9 Oct 2008 Jian-Guo Li
973  !
974  ! Subroutine Interface:
975 
976  Subroutine w3acturn( NDirc, NFreq, Alpha, Spectr )
977 
978  ! Description:
979  ! Rotates wave spectrum anticlockwise by angle alpha
980  ! Routine is distinct from W3SPECTN since orders spectrum as dirn, freq
981  !
982  ! Subroutine arguments
983  INTEGER, INTENT(IN) :: NFreq, NDirc ! No. freq and dirn bins
984  REAL, INTENT(IN) :: Alpha ! Turning angle (degrees)
985  REAL, INTENT(INOUT) :: Spectr(NDirc, NFreq) ! Wave action in/out
986 
987  ! Local variables
988  INTEGER :: ii, jj, kk, nsft
989  REAL :: Ddirc, frac, CNST
990  REAL, Dimension(NFreq) :: Wrkfrq, Tmpfrq
991  REAL, Dimension(NDirc,NFreq):: Wrkspc
992 
993  ! Check input bin numbers
994  IF( (nfreq .LT. 0) .OR. (ndirc .LT. 0) ) THEN
995  print*, " Invalid bin number NF or ND", nfreq, ndirc
996  RETURN
997  ELSE
998  ddirc=360.0/float(ndirc)
999  ENDIF
1000 
1001  ! Work out shift bin number and fraction
1002 
1003  cnst=alpha/ddirc
1004  nsft=int( cnst )
1005  frac= cnst - float( nsft )
1006  ! PRINT*, ' nsft and frac =', nsft, frac
1007 
1008  ! Shift nsft bins if >=1
1009  IF( abs(nsft) .GE. 1 ) THEN
1010  DO ii=1, ndirc
1011 
1012  ! Wave spectral direction bin number is assumed to increase Anti-clockwise from EAST
1013  ! So shift nsft bins anticlockwise results in local bin number decreasing by nsft
1014  jj=ii - nsft
1015 
1016  ! As nsft may be either positive or negative depends on alpha, wrapping may
1017  ! happen in either ends of the bin number train
1018  IF( jj > ndirc ) jj=jj - ndirc
1019  IF( jj < 1 ) jj=jj + ndirc
1020 
1021  ! Copy the selected bin to the loop bin number
1022  wrkspc(ii,:)=spectr(jj,:)
1023 
1024  ENDDO
1025 
1026  ! If nsft=0, no need to shift, simply copy
1027  ELSE
1028  wrkspc = spectr
1029  ENDIF
1030 
1031  ! Pass fraction of wave energy in frac direction
1032  ! Wave spectral direction bin number is assumed to increase anti-clockwise from EAST
1033  ! So positive frac or anticlock case, smaller bin upstream
1034  IF( frac > 0.0 ) THEN
1035  tmpfrq=wrkspc(ndirc,:)*frac
1036  DO kk=1, ndirc
1037  wrkfrq=wrkspc(kk,:)*frac
1038  spectr(kk,:)=wrkspc(kk,:) - wrkfrq + tmpfrq
1039  tmpfrq=wrkfrq
1040  ENDDO
1041  ELSE
1042  ! Negative or clockwise case, larger bin upstream
1043  tmpfrq=wrkspc(1,:)*frac
1044  DO kk=ndirc, 1, -1
1045  wrkfrq=wrkspc(kk,:)*frac
1046  spectr(kk,:)=wrkspc(kk,:) + wrkfrq - tmpfrq
1047  tmpfrq=wrkfrq
1048  ENDDO
1049  ENDIF
1050 
1051  ! Spectral turning completed
1052 
1053  RETURN
1054  END SUBROUTINE w3acturn
1055  !
1056  !Li +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1057  !Li
1058  !Li Merged UM source code for rotated grid, consisting the following
1059  !Li original subroutines in UM 6.1
1060  !Li LLTOEQ1A WCOEFF1A and LBCROTWINDS1
1061  !Li The last subroutine is modified to process only one level winds
1062  !Li cpp directives are removed and required header C_Pi.h inserted.
1063  !Li Jian-Guo Li 26 May 2005
1064  !Li
1065  !Li The WCOEFF1A subroutine is merged into LLTOEQ to reduce repetition
1066  !Li of the same calculations. Subroutine interface changed to
1067  !Li LLTOEQANGLE
1068  !Li Jian-GUo Li 23 Aug 2005
1069  !Li
1070  !Li Subroutine W3LLTOEQ --------------------------------------------
1071  !Li
1072  !Li Purpose: Calculates latitude and longitude on equatorial
1073  !Li latitude-longitude (eq) grid used in regional
1074  !Li models from input arrays of latitude and
1075  !Li longitude on standard grid. Both input and output
1076  !Li latitudes and longitudes are in degrees.
1077  !Li Also calculate rotation angle in degree to tranform
1078  !Li standard wind velocity into equatorial wind.
1079  !Li Valid for 0<PHI_POLE<90 or new pole in N. hemisphere.
1080  !Li
1081  !* Arguments:--------------------------------------------------------
1082  SUBROUTINE w3lltoeq ( PHI, LAMBDA, PHI_EQ, LAMBDA_EQ, ANGLED, PHI_POLE, &
1083  LAMBDA_POLE, POINTS )
1085  INTEGER:: POINTS !IN Number of points to be processed
1086 
1087  REAL :: PHI_POLE, & !IN Latitude of equatorial lat-lon pole
1088  & LAMBDA_POLE !INOUT Longitude of equatorial lat-lon pole
1089 
1090  REAL, DIMENSION(POINTS) :: &
1091  & PHI, & !IN Latitude
1092  & LAMBDA, & !IN Longitude
1093  & ANGLED, & !OUT turning angle in deg for standard wind
1094  & LAMBDA_EQ, & !OUT Longitude in equatorial lat-lon coords
1095  & PHI_EQ !OUT Latitude in equatorial lat-lon coords
1096 
1097  ! Define local varables:-----------------------------------------------
1098  REAL(KIND=8) :: a_lambda, a_phi, e_lambda, e_phi, sin_phi_pole, cos_phi_pole, &
1099  term1, term2, arg, lambda_zero, lambda_pole_keep
1100  INTEGER :: I
1101 
1102  REAL(KIND=8), parameter :: small=1.0e-6
1103 
1104  ! Double precision versions of values in constants.ftn:
1105  REAL(KIND=8), parameter :: pi = 3.141592653589793
1106  REAL(KIND=8), parameter :: recip_pi_over_180 = 180. / pi
1107  REAL(KIND=8), parameter :: pi_over_180 = pi / 180.
1108 
1109  !*----------------------------------------------------------------------
1110 
1111  ! 1. Initialise local constants
1112  ! Scale lambda pole to range -180 to 180 degs
1113  lambda_pole_keep=lambda_pole
1114  IF (lambda_pole.LE.-180.0) lambda_pole=lambda_pole+360.d0
1115  IF (lambda_pole.GT. 180.0) lambda_pole=lambda_pole-360.d0
1116 
1117  ! Latitude of zeroth meridian
1118  lambda_zero=lambda_pole+180.d0
1119  ! Sine and cosine of latitude of eq pole
1120  IF (phi_pole >= 0.0) THEN
1121  sin_phi_pole = sin(pi_over_180*phi_pole)
1122  cos_phi_pole = cos(pi_over_180*phi_pole)
1123  ELSE
1124  sin_phi_pole = -sin(pi_over_180*phi_pole)
1125  cos_phi_pole = -cos(pi_over_180*phi_pole)
1126  ENDIF
1127 
1128  ! 2. Transform from standard to equatorial latitude-longitude
1129 
1130  DO i= 1, points
1131 
1132  ! Scale longitude to range -180 to +180 degs
1133 
1134  a_lambda=lambda(i)-lambda_zero
1135  IF(a_lambda.GT. 180.0) a_lambda=a_lambda-360.d0
1136  IF(a_lambda.LE.-180.0) a_lambda=a_lambda+360.d0
1137 
1138  ! Convert latitude & longitude to radians
1139 
1140  a_lambda=pi_over_180*a_lambda
1141  a_phi=pi_over_180*phi(i)
1142 
1143  ! Compute eq latitude using equation (4.4)
1144 
1145  arg=-cos_phi_pole*cos(a_phi)*cos(a_lambda) + sin_phi_pole*sin(a_phi)
1146  arg=min(arg, 1.d0)
1147  arg=max(arg,-1.d0)
1148  e_phi=asin(arg)
1149  phi_eq(i)=recip_pi_over_180*e_phi
1150 
1151  ! Compute eq longitude using equation (4.6)
1152 
1153  term1 = sin_phi_pole*cos(a_phi)*cos(a_lambda) + cos_phi_pole*sin(a_phi)
1154  term2 = cos(e_phi)
1155  IF(term2 .LT. small) THEN
1156  e_lambda=0.d0
1157  ELSE
1158  arg=term1/term2
1159  arg=min(arg, 1.d0)
1160  arg=max(arg,-1.d0)
1161  e_lambda=recip_pi_over_180*acos(arg)
1162  e_lambda=sign(e_lambda,a_lambda)
1163  ENDIF
1164 
1165  ! Scale longitude to range 0 to 360 degs
1166 
1167  IF(e_lambda.GE.360.0) e_lambda=e_lambda-360.d0
1168  IF(e_lambda.LT. 0.0) e_lambda=e_lambda+360.d0
1169  lambda_eq(i)=e_lambda
1170 
1171  !Li Calculate turning angle for standard wind velocity
1172 
1173  e_lambda=pi_over_180*lambda_eq(i)
1174 
1175  ! Formulae used are from eqs (4.19) and (4.21)
1176 
1177  term2=sin(e_lambda)
1178  arg= sin(a_lambda)*term2*sin_phi_pole &
1179  & +cos(a_lambda)*cos(e_lambda)
1180  arg=min(arg, 1.d0)
1181  arg=max(arg,-1.d0)
1182  term1=recip_pi_over_180*acos(arg)
1183  angled(i)=sign(term1,term2)
1184  !Li
1185 
1186  ENDDO
1187 
1188  ! Reset Lambda pole to the setting on entry to subroutine
1189  lambda_pole=lambda_pole_keep
1190 
1191  RETURN
1192  END SUBROUTINE w3lltoeq
1193  !
1194  !Li +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1195  !Li
1196  !Li Merged UM source code for rotated grid, consiting the following
1197  !Li original subroutines in UM 6.1
1198  !Li EQTOLL1A WCOEFF1A and LBCROTWINDS1
1199  !Li The last subroutine is modified to process only one level winds
1200  !Li cpp directives are removed and required header C_Pi.h inserted.
1201  !Li Jian-Guo Li 26 May 2005
1202  !Li
1203  !Li The WCOEFF1A subroutine is merged into EQTOLL to reduce repetition
1204  !Li of the same calculations. Subroutine interface changed to
1205  !Li EQTOLLANGLE
1206  !Li First created: Jian-GUo Li 23 Aug 2005
1207  !Li Last modified: Jian-GUo Li 25 Feb 2008
1208  !Li
1209  !Li Subroutine W3EQTOLL --------------------------------------------
1210  !Li
1211  !Li Purpose: Calculates latitude and longitude on standard grid
1212  !Li from input arrays of latitude and longitude on
1213  !Li equatorial latitude-longitude (eq) grid used
1214  !Li in regional models. Both input and output latitudes
1215  !Li and longitudes are in degrees.
1216  !Li Also calculate rotation angle in degree to tranform
1217  !Li standard wind velocity into equatorial wind.
1218  !Li Valid for 0<PHI_POLE<90 or new pole in N. hemisphere.
1219  !Li
1220  !Li Arguments:--------------------------------------------------------
1221 
1222  SUBROUTINE w3eqtoll( PHI_EQ, LAMBDA_EQ, PHI, LAMBDA, &
1223  & ANGLED, PHI_POLE, LAMBDA_POLE, POINTS )
1225  INTEGER:: POINTS !IN Number of points to be processed
1226 
1227  REAL :: PHI_POLE, & !IN Latitude of equatorial lat-lon pole
1228  & LAMBDA_POLE !IN Longitude of equatorial lat-lon pole
1229 
1230  REAL, DIMENSION(POINTS) :: &
1231  & PHI, & !OUT Latitude
1232  & LAMBDA, & !OUT Longitude (0 =< LON < 360)
1233  & ANGLED, & !OUT turning angle in deg for standard wind
1234  & LAMBDA_EQ, & !IN Longitude in equatorial lat-lon coords
1235  & PHI_EQ !IN Latitude in equatorial lat-lon coords
1236 
1237  ! Local varables:------------------------------------------------------
1238  REAL(KIND=8) :: e_lambda, e_phi, a_lambda, a_phi, &
1239  sin_phi_pole, cos_phi_pole, &
1240  term1, term2, arg, lambda_zero
1241  INTEGER :: I
1242 
1243  REAL(KIND=8), parameter :: small=1.0e-6
1244 
1245  ! Double precision versions of values in constants.ftn:
1246  REAL(KIND=8), parameter :: pi = 3.141592653589793
1247  REAL(KIND=8), parameter :: recip_pi_over_180 = 180. / pi
1248  REAL(KIND=8), parameter :: pi_over_180 = pi / 180.
1249 
1250  ! ----------------------------------------------------------------------
1251 
1252  ! 1. Initialise local constants
1253 
1254  ! Latitude of zeroth meridian
1255  lambda_zero=lambda_pole+180.d0
1256  ! Sine and cosine of latitude of eq pole
1257  IF (phi_pole >= 0.0) THEN
1258  sin_phi_pole = sin(pi_over_180*phi_pole)
1259  cos_phi_pole = cos(pi_over_180*phi_pole)
1260  ELSE
1261  sin_phi_pole = -sin(pi_over_180*phi_pole)
1262  cos_phi_pole = -cos(pi_over_180*phi_pole)
1263  ENDIF
1264 
1265  ! 2. Transform from equatorial to standard latitude-longitude
1266 
1267  DO i= 1, points
1268 
1269  ! Scale eq longitude to range -180 to +180 degs
1270 
1271  e_lambda=lambda_eq(i)
1272  IF(e_lambda.GT. 180.0) e_lambda=e_lambda-360.d0
1273  IF(e_lambda.LT.-180.0) e_lambda=e_lambda+360.d0
1274 
1275  ! Convert eq latitude & longitude to radians
1276 
1277  e_lambda=pi_over_180*e_lambda
1278  e_phi=pi_over_180*phi_eq(i)
1279 
1280  ! Compute latitude using equation (4.7)
1281 
1282  arg=cos_phi_pole*cos(e_phi)*cos(e_lambda) + sin_phi_pole*sin(e_phi)
1283  arg=min(arg, 1.d0)
1284  arg=max(arg,-1.d0)
1285  a_phi=asin(arg)
1286  phi(i)=recip_pi_over_180*a_phi
1287 
1288  ! Compute longitude using equation (4.8)
1289 
1290  term1 = cos(e_phi)*sin_phi_pole*cos(e_lambda) - sin(e_phi)*cos_phi_pole
1291  term2 = cos(a_phi)
1292  IF(term2.LT.small) THEN
1293  a_lambda=0.d0
1294  ELSE
1295  arg=term1/term2
1296  arg=min(arg, 1.d0)
1297  arg=max(arg,-1.d0)
1298  a_lambda=recip_pi_over_180*acos(arg)
1299  a_lambda=sign(a_lambda,e_lambda)
1300  a_lambda=a_lambda+lambda_zero
1301  END IF
1302 
1303  ! Scale longitude to range 0 to 360 degs
1304 
1305  IF(a_lambda.GE.360.0) a_lambda=a_lambda-360.d0
1306  IF(a_lambda.LT. 0.0) a_lambda=a_lambda+360.d0
1307  lambda(i)=a_lambda
1308 
1309  !Li Calculate turning angle for standard wind velocity
1310 
1311  a_lambda=pi_over_180*(lambda(i)-lambda_zero)
1312 
1313  ! Formulae used are from eqs (4.19) and (4.21)
1314 
1315  term2=sin(e_lambda)
1316  arg=sin(a_lambda)*term2*sin_phi_pole &
1317  & +cos(a_lambda)*cos(e_lambda)
1318  arg=min(arg, 1.d0)
1319  arg=max(arg,-1.d0)
1320  term1=recip_pi_over_180*acos(arg)
1321  angled(i)=sign(term1,term2)
1322  !Li
1323 
1324  ENDDO
1325 
1326  RETURN
1327  END SUBROUTINE w3eqtoll
1328 
1329  !Li
1330  !/ ------------------------------------------------------------------- /
1331  !/ ------------------------------------------------------------------- /
1332  SUBROUTINE w3thrtn ( NSEA, THETA, AnglD, Degrees )
1333  !/
1334  !/ +-----------------------------------+
1335  !/ | WAVEWATCH III NOAA/NMC |
1336  !/ | A. Saulter |
1337  !/ | FORTRAN 90 |
1338  !/ | Last update : 01-Mar-2018 |
1339  !/ +-----------------------------------+
1340  !/
1341  !/ 01-Mar-2018 : Added subroutine ( version 6.02 )
1342  !
1343  ! 1. Purpose :
1344  ! Subroutine to de-rotate directions from rotated to standard pole
1345  ! reference system
1346  !
1347  ! 2. Method:
1348  ! Rotates x,y vectors anticlockwise by angle alpha in radians
1349  !
1350  !/ ------------------------------------------------------------------- /
1351  USE constants, ONLY : dera, tpi, undef
1352  !
1353  !/ ------------------------------------------------------------------- /
1354  !/ Parameter list
1355  !/
1356  INTEGER, INTENT(IN) :: NSEA ! Number of sea points
1357  REAL, INTENT(IN) :: AnglD(NSEA) ! Turning angle (degrees)
1358  LOGICAL, INTENT(IN) :: Degrees ! Use degrees or radians
1359  REAL, INTENT(INOUT) :: THETA(NSEA) ! Direction seapoint array
1360  !
1361  !/ ------------------------------------------------------------------- /
1362  !/ Local parameters
1363  !/
1364  INTEGER :: ISEA
1365  !
1366  !/ ------------------------------------------------------------------- /
1367  ! Apply the rotation
1368  !
1369  DO isea=1, nsea
1370  IF ( theta(isea) .NE. undef ) THEN
1371  IF ( degrees ) THEN
1372  theta(isea) = theta(isea) - angld(isea)
1373  IF ( theta(isea) .LT. 0 ) theta(isea) = theta(isea) + 360.0
1374  ELSE
1375  theta(isea) = theta(isea) - angld(isea)*dera
1376  IF ( theta(isea) .LT. 0 ) theta(isea) = theta(isea) + tpi
1377  END IF
1378  ENDIF
1379  END DO
1380 
1381  RETURN
1382  END SUBROUTINE w3thrtn
1383  !
1384  !/ ------------------------------------------------------------------- /
1385  !/ ------------------------------------------------------------------- /
1386  SUBROUTINE w3xyrtn ( NSEA, XVEC, YVEC, AnglD )
1387  !/
1388  !/ +-----------------------------------+
1389  !/ | WAVEWATCH III NOAA/NMC |
1390  !/ | A. Saulter |
1391  !/ | FORTRAN 90 |
1392  !/ | Last update : 01-Mar-2018 |
1393  !/ +-----------------------------------+
1394  !/
1395  !/ 01-Mar-2018 : Added subroutine ( version 6.02 )
1396  !
1397  ! 1. Purpose :
1398  ! Subroutine to de-rotate x,y vectors from rotated to standard pole
1399  ! reference system
1400  !
1401  ! 2. Method:
1402  ! Rotates x,y vectors anticlockwise by angle alpha in radians
1403  !
1404  !/ ------------------------------------------------------------------- /
1405  USE constants, ONLY : dera, tpi, undef
1406  !
1407  !/ ------------------------------------------------------------------- /
1408  !/ Parameter list
1409  !/
1410  INTEGER, INTENT(IN) :: NSEA ! Number of sea points
1411  REAL, INTENT(IN) :: AnglD(NSEA) ! Turning angle (degrees)
1412  REAL, INTENT(INOUT) :: XVEC(NSEA), YVEC(NSEA)
1413  !
1414  !/ ------------------------------------------------------------------- /
1415  !/ Local parameters
1416  !/
1417  INTEGER :: ISEA
1418  REAL :: XVTMP, YVTMP
1419  !
1420  !/ ------------------------------------------------------------------- /
1421  ! Apply the rotation
1422  !
1423  DO isea=1, nsea
1424  IF (( xvec(isea) .NE. undef ) .AND. &
1425  ( yvec(isea) .NE. undef )) THEN
1426  xvtmp = xvec(isea)*cos(angld(isea)*dera) + yvec(isea)*sin(angld(isea)*dera)
1427  yvtmp = yvec(isea)*cos(angld(isea)*dera) - xvec(isea)*sin(angld(isea)*dera)
1428  xvec(isea) = xvtmp
1429  yvec(isea) = yvtmp
1430  END IF
1431  END DO
1432 
1433  RETURN
1434  END SUBROUTINE w3xyrtn
1435  !
1436  !/ ------------------------------------------------------------------- /
1437  !/ ------------------------------------------------------------------- /
1438  !/
1439  SUBROUTINE strsplit(STRING,TAB)
1440  !/
1441  !/ +-----------------------------------+
1442  !/ | WAVEWATCH III NOAA/NCEP |
1443  !/ | M. Accensi |
1444  !/ | FORTRAN 90 |
1445  !/ | Last update : 29-Apr-2013 !
1446  !/ +-----------------------------------+
1447  !/
1448  !/ 29-Mar-2013 : Origination. ( version 4.10 )
1449  !/
1450  ! 1. Purpose :
1451  !
1452  ! Splits string into words
1453  !
1454  ! 2. Method :
1455  !
1456  ! finds spaces and loops
1457  !
1458  ! 3. Parameters :
1459  !
1460  ! Parameter list
1461  ! ----------------------------------------------------------------
1462  ! STRING Str O String to be splitted
1463  ! TAB Str O Array of strings
1464  ! ----------------------------------------------------------------
1465  !
1466  CHARACTER(LEN=*), intent(IN) :: STRING
1467  CHARACTER(LEN=100), intent(INOUT) :: TAB(*)
1468  INTEGER :: cnt, I
1469  CHARACTER(LEN=1024) :: tmp_str, ori_str
1470 
1471  ! initializes arrays
1472  ori_str=adjustl(trim(string))
1473  tmp_str=ori_str
1474  cnt=0
1475 
1476  ! counts the number of substrings
1477  DO WHILE ((index(tmp_str,' ').NE.0) .AND. (len_trim(tmp_str).NE.0))
1478  tmp_str=adjustl(tmp_str(index(tmp_str,' ')+1:))
1479  cnt=cnt+1
1480  ENDDO
1481  !
1482  ! reinitializes arrays
1483  !
1484  tmp_str=ori_str
1485  ! loops on each substring
1486  DO i=1,cnt
1487  tab(i)=tmp_str(:index(tmp_str,' '))
1488  tmp_str=adjustl(tmp_str(index(tmp_str,' ')+1:))
1489  END DO
1490 
1491  RETURN
1492  !/
1493  !/ End of STRSPLIT ----------------------------------------------------- /
1494  !/
1495  END SUBROUTINE strsplit
1496  !/
1497 
1498  !/ ------------------------------------------------------------------- /
1499  SUBROUTINE str_to_upper(STR)
1500  character(*), intent(inout) :: str
1501  integer :: i
1502 
1503  DO i = 1, len(str)
1504  select case(str(i:i))
1505  case("a":"z")
1506  str(i:i) = achar(iachar(str(i:i))-32)
1507  end select
1508  END DO
1509  !/ End of STR_TO_UPPER
1510  !/ ------------------------------------------------------------------- /
1511  END SUBROUTINE str_to_upper
1512 
1513  !**********************************************************************
1514  !* *
1515 #ifdef W3_T
1516  !**********************************************************************
1517  SUBROUTINE ssort1 (X, Y, N, KFLAG)
1518  !***BEGIN PROLOGUE SSORT
1519  !***PURPOSE Sort an array and optionally make the same interchanges in
1520  ! an auxiliary array. The array may be sorted in increasing
1521  ! or decreasing order. A slightly modified QUICKSORT
1522  ! algorithm is used.
1523  !***LIBRARY SLATEC
1524  !***CATEGORY N6A2B
1525  !***TYPE SINGLE PRECISION (SSORT-S, DSORT-D, ISORT-I)
1526  !***KEYWORDS SINGLETON QUICKSORT, SORT, SORTING
1527  !***AUTHOR Jones, R. E., (SNLA)
1528  ! Wisniewski, J. A., (SNLA)
1529  !***DESCRIPTION
1530  !
1531  ! SSORT sorts array X and optionally makes the same interchanges in
1532  ! array Y. The array X may be sorted in increasing order or
1533  ! decreasing order. A slightly modified quicksort algorithm is used.
1534  !
1535  ! Description of Parameters
1536  ! X - array of values to be sorted (usually abscissas)
1537  ! Y - array to be (optionally) carried along
1538  ! N - number of values in array X to be sorted
1539  ! KFLAG - control parameter
1540  ! = 2 means sort X in increasing order and carry Y along.
1541  ! = 1 means sort X in increasing order (ignoring Y)
1542  ! = -1 means sort X in decreasing order (ignoring Y)
1543  ! = -2 means sort X in decreasing order and carry Y along.
1544  !
1545  !***REFERENCES R. C. Singleton, Algorithm 347, An efficient algorithm
1546  ! for sorting with minimal storage, Communications of
1547  ! the ACM, 12, 3 (1969), pp. 185-187.
1548  !***REVISION HISTORY (YYMMDD)
1549  ! 761101 DATE WRITTEN
1550  ! 761118 Modified to use the Singleton quicksort algorithm. (JAW)
1551  ! 890531 Changed all specific intrinsics to generic. (WRB)
1552  ! 890831 Modified array declarations. (WRB)
1553  ! 891009 Removed unreferenced statement labels. (WRB)
1554  ! 891024 Changed category. (WRB)
1555  ! 891024 REVISION DATE from Version 3.2
1556  ! 891214 Prologue converted to Version 4.0 format. (BAB)
1557  ! 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
1558  ! 901012 Declared all variables; changed X,Y to SX,SY. (M. McClain)
1559  ! 920501 Reformatted the REFERENCES section. (DWL, WRB)
1560  ! 920519 Clarified error messages. (DWL)
1561  ! 920801 Declarations section rebuilt and code restructured to use
1562  ! IF-THEN-ELSE-ENDIF. (RWC, WRB)
1563  !***END PROLOGUE SSORT
1564  ! .. Scalar Arguments ..
1565  INTEGER KFLAG, N
1566  ! .. Array Arguments ..
1567  real*4 x(*), y(*)
1568  ! .. Local Scalars ..
1569  real*4 r, t, tt, tty, ty
1570  INTEGER I, IJ, J, K, KK, L, M, NN
1571  ! .. Local Arrays ..
1572  INTEGER IL(21), IU(21)
1573  ! .. External Subroutines ..
1574  ! None
1575  ! .. Intrinsic Functions ..
1576  INTRINSIC abs, int
1577  !***FIRST EXECUTABLE STATEMENT SSORT
1578  nn = n
1579  IF (nn .LT. 1) THEN
1580  WRITE (*,*) 'The number of values to be sorted is not positive.'
1581  RETURN
1582  ENDIF
1583  !
1584  kk = abs(kflag)
1585  IF (kk.NE.1 .AND. kk.NE.2) THEN
1586  WRITE (*,*) 'The sort control parameter, K, is not 2, 1, -1, or -2.'
1587  RETURN
1588  ENDIF
1589  !
1590  ! Alter array X to get decreasing order if needed
1591  !
1592  IF (kflag .LE. -1) THEN
1593  DO i=1,nn
1594  x(i) = -x(i)
1595  end do
1596  ENDIF
1597  !
1598  IF (kk .EQ. 2) GO TO 100
1599  !
1600  ! Sort X only
1601  !
1602  m = 1
1603  i = 1
1604  j = nn
1605  r = 0.375e0
1606  !
1607 20 IF (i .EQ. j) GO TO 60
1608  IF (r .LE. 0.5898437e0) THEN
1609  r = r+3.90625e-2
1610  ELSE
1611  r = r-0.21875e0
1612  ENDIF
1613  !
1614 30 k = i
1615  !
1616  ! Select a central element of the array and save it in location T
1617  !
1618  ij = i + int((j-i)*r)
1619  t = x(ij)
1620  !
1621  ! If first element of array is greater than T, interchange with T
1622  !
1623  IF (x(i) .GT. t) THEN
1624  x(ij) = x(i)
1625  x(i) = t
1626  t = x(ij)
1627  ENDIF
1628  l = j
1629  !
1630  ! If last element of array is less than than T, interchange with T
1631  !
1632  IF (x(j) .LT. t) THEN
1633  x(ij) = x(j)
1634  x(j) = t
1635  t = x(ij)
1636  !
1637  ! If first element of array is greater than T, interchange with T
1638  !
1639  IF (x(i) .GT. t) THEN
1640  x(ij) = x(i)
1641  x(i) = t
1642  t = x(ij)
1643  ENDIF
1644  ENDIF
1645  !
1646  ! Find an element in the second half of the array which is smaller
1647  ! than T
1648  !
1649 40 l = l-1
1650  IF (x(l) .GT. t) GO TO 40
1651  !
1652  ! Find an element in the first half of the array which is greater
1653  ! than T
1654  !
1655 50 k = k+1
1656  IF (x(k) .LT. t) GO TO 50
1657  !
1658  ! Interchange these elements
1659  !
1660  IF (k .LE. l) THEN
1661  tt = x(l)
1662  x(l) = x(k)
1663  x(k) = tt
1664  GO TO 40
1665  ENDIF
1666  !
1667  ! Save upper and lower subscripts of the array yet to be sorted
1668  !
1669  IF (l-i .GT. j-k) THEN
1670  il(m) = i
1671  iu(m) = l
1672  i = k
1673  m = m+1
1674  ELSE
1675  il(m) = k
1676  iu(m) = j
1677  j = l
1678  m = m+1
1679  ENDIF
1680  GO TO 70
1681  !
1682  ! Begin again on another portion of the unsorted array
1683  !
1684 60 m = m-1
1685  IF (m .EQ. 0) GO TO 190
1686  i = il(m)
1687  j = iu(m)
1688  !
1689 70 IF (j-i .GE. 1) GO TO 30
1690  IF (i .EQ. 1) GO TO 20
1691  i = i-1
1692  !
1693 80 i = i+1
1694  IF (i .EQ. j) GO TO 60
1695  t = x(i+1)
1696  IF (x(i) .LE. t) GO TO 80
1697  k = i
1698  !
1699 90 x(k+1) = x(k)
1700  k = k-1
1701  IF (t .LT. x(k)) GO TO 90
1702  x(k+1) = t
1703  GO TO 80
1704  !
1705  ! Sort X and carry Y along
1706  !
1707 100 m = 1
1708  i = 1
1709  j = nn
1710  r = 0.375e0
1711  !
1712 110 IF (i .EQ. j) GO TO 150
1713  IF (r .LE. 0.5898437e0) THEN
1714  r = r+3.90625e-2
1715  ELSE
1716  r = r-0.21875e0
1717  ENDIF
1718  !
1719 120 k = i
1720  !
1721  ! Select a central element of the array and save it in location T
1722  !
1723  ij = i + int((j-i)*r)
1724  t = x(ij)
1725  ty = y(ij)
1726  !
1727  ! If first element of array is greater than T, interchange with T
1728  !
1729  IF (x(i) .GT. t) THEN
1730  x(ij) = x(i)
1731  x(i) = t
1732  t = x(ij)
1733  y(ij) = y(i)
1734  y(i) = ty
1735  ty = y(ij)
1736  ENDIF
1737  l = j
1738  !
1739  ! If last element of array is less than T, interchange with T
1740  !
1741  IF (x(j) .LT. t) THEN
1742  x(ij) = x(j)
1743  x(j) = t
1744  t = x(ij)
1745  y(ij) = y(j)
1746  y(j) = ty
1747  ty = y(ij)
1748  !
1749  ! If first element of array is greater than T, interchange with T
1750  !
1751  IF (x(i) .GT. t) THEN
1752  x(ij) = x(i)
1753  x(i) = t
1754  t = x(ij)
1755  y(ij) = y(i)
1756  y(i) = ty
1757  ty = y(ij)
1758  ENDIF
1759  ENDIF
1760  !
1761  ! Find an element in the second half of the array which is smaller
1762  ! than T
1763  !
1764 130 l = l-1
1765  IF (x(l) .GT. t) GO TO 130
1766  !
1767  ! Find an element in the first half of the array which is greater
1768  ! than T
1769  !
1770 140 k = k+1
1771  IF (x(k) .LT. t) GO TO 140
1772  !
1773  ! Interchange these elements
1774  !
1775  IF (k .LE. l) THEN
1776  tt = x(l)
1777  x(l) = x(k)
1778  x(k) = tt
1779  tty = y(l)
1780  y(l) = y(k)
1781  y(k) = tty
1782  GO TO 130
1783  ENDIF
1784  !
1785  ! Save upper and lower subscripts of the array yet to be sorted
1786  !
1787  IF (l-i .GT. j-k) THEN
1788  il(m) = i
1789  iu(m) = l
1790  i = k
1791  m = m+1
1792  ELSE
1793  il(m) = k
1794  iu(m) = j
1795  j = l
1796  m = m+1
1797  ENDIF
1798  GO TO 160
1799  !
1800  ! Begin again on another portion of the unsorted array
1801  !
1802 150 m = m-1
1803  IF (m .EQ. 0) GO TO 190
1804  i = il(m)
1805  j = iu(m)
1806  !
1807 160 IF (j-i .GE. 1) GO TO 120
1808  IF (i .EQ. 1) GO TO 110
1809  i = i-1
1810  !
1811 170 i = i+1
1812  IF (i .EQ. j) GO TO 150
1813  t = x(i+1)
1814  ty = y(i+1)
1815  IF (x(i) .LE. t) GO TO 170
1816  k = i
1817  !
1818 180 x(k+1) = x(k)
1819  y(k+1) = y(k)
1820  k = k-1
1821  IF (t .LT. x(k)) GO TO 180
1822  x(k+1) = t
1823  y(k+1) = ty
1824  GO TO 170
1825  !
1826  ! Clean up
1827  !
1828 190 IF (kflag .LE. -1) THEN
1829  DO i=1,nn
1830  x(i) = -x(i)
1831  end do
1832  ENDIF
1833  RETURN
1834  END SUBROUTINE ssort1
1835 
1836 #endif
1837 
1838  !*********************************************************************
1839  SUBROUTINE diagonalize(a1,d,v,nrot)
1840  !*********************************************************************
1841  INTEGER, INTENT(out) :: nrot
1842  DOUBLE PRECISION, DIMENSION(:) , INTENT(OUT) ::d
1843  DOUBLE PRECISION, DIMENSION(:,:), INTENT(IN) ::a1 ! Modified from INOUT to IN by F.A. on 2018/01/21
1844  DOUBLE PRECISION, DIMENSION(:,:), INTENT(OUT) ::v
1845 
1846  INTEGER i,j,ip,iq,n
1847  DOUBLE PRECISION c,g,h,s,sm,t,tau,theta,tresh
1848  DOUBLE PRECISION , DIMENSION(size(d)) ::b,z
1849  DOUBLE PRECISION, DIMENSION(size(d),size(d)) :: a
1850  LOGICAL, DIMENSION(size(d),size(d)) :: upper_triangle
1851 
1852  a=a1
1853  n=size(d)
1854  v(:,:)=0.
1855  upper_triangle(:,:)=.false.
1856  DO i=1,n
1857  v(i,i)=1.
1858  b(i)=a(i,i)
1859  DO j=i+1,n
1860  upper_triangle(i,j)=.true.
1861  ENDDO
1862  ENDDO
1863  d(:)=b(:)
1864  z(:)=0.0
1865  nrot=0
1866  DO i=1,50
1867  sm=sum(abs(a),mask=upper_triangle)
1868  IF (sm.EQ.0.0) RETURN
1869  tresh=merge(0.2*sm/n**2,0.0d0,i<4)
1870  DO ip=1,n-1
1871  do iq=ip+1,n
1872  g=100.0*abs(a(ip,iq))
1873  IF((i > 4).AND.(abs(d(ip))+g.EQ.abs(d(ip))) &
1874  .AND.(abs(d(iq))+g.EQ.abs(d(iq)))) THEN
1875  a(ip,iq)=0.0
1876  ELSE IF (abs(a(ip,iq)) > tresh) THEN
1877  h=d(iq)-d(ip)
1878  if (abs(h)+g == abs(h)) THEN
1879  t=a(ip,iq)/h
1880  ELSE
1881  theta=0.5*h/a(ip,iq)
1882  t=1.0/(abs(theta)+sqrt(1.0+theta**2))
1883  IF ( theta < 0.0) t=-t
1884  ENDIF
1885  c=1.0/sqrt(1+t**2)
1886  s=t*c
1887  tau=s/(1.0+c)
1888  h=t*a(ip,iq)
1889  z(ip)=z(ip)-h
1890  z(iq)=z(iq)+h
1891  d(ip)=d(ip)-h
1892  d(iq)=d(iq)+h
1893  a(ip,iq)=0.0
1894  IF (ip.GE.1) CALL rotate(a(1:ip-1,ip),a(1:ip-1,iq))
1895  !The IF test was added by F.A. (2005/04/04) because of the following error:
1896  !Subscript out of range. Location: line 593 column 36 of 'cb_botsc.f90'
1897  !Subscript number 1 has value 0 in array 'A'
1898  CALL rotate(a(ip,ip+1:iq-1),a(ip+1:iq-1,iq))
1899  CALL rotate(a(ip,iq+1:n),a(iq,iq+1:n))
1900  CALL rotate(v(:,ip),v(:,iq))
1901  nrot=nrot+1
1902  ENDIF
1903  ENDDO
1904  ENDDO
1905  b(:)=b(:)+z(:)
1906  d(:)=b(:)
1907  z(:)=0.0
1908  ENDDO
1909  WRITE(6,*) 'Too many iterations in DIAGONALIZE'
1910  CONTAINS
1911  SUBROUTINE rotate(X1,X2)
1912  DOUBLE PRECISION, DIMENSION(:), INTENT(INOUT) :: X1,X2
1913  DOUBLE PRECISION, DIMENSION(size(X1)) :: MEM
1914  mem(:)=x1(:)
1915  x1(:)=x1(:)-s*(x2(:)+x1(:)*tau)
1916  x2(:)=x2(:)+s*(mem(:)-x2(:)*tau)
1917  END SUBROUTINE rotate
1918  END SUBROUTINE diagonalize
1919 
1920  !/ ------------------------------------------------------------------- /
1921  SUBROUTINE uv_to_mag_dir(U, V, NSEA, MAG, DIR, TOLERANCE, CONV)
1922  !/
1923  !/ +-----------------------------------+
1924  !/ | WAVEWATCH III NOAA/NCEP |
1925  !/ | C. Bunney |
1926  !/ | FORTRAN 90 |
1927  !/ | Last update : 15-Jan-2021 |
1928  !/ +-----------------------------------+
1929  !/
1930  !/ 15-Jan-2021 : Creation ( version 7.12 )
1931  !/
1932  ! 1. Purpose :
1933  !
1934  ! Converts seapoint arrays formulated as U/V vectors into magnitude
1935  ! and direction arrays.
1936  !
1937  ! If MAG and DIR input parameters are not specificed then the
1938  ! conversion is performed in-place (U => MAG, v => DIR).
1939  !
1940  ! 2. Parameters
1941  !
1942  ! Parameter list
1943  ! ----------------------------------------------------------------
1944  ! U/V R.Arr I Array of U/V components
1945  ! NSEA Int I Number of sea points
1946  ! MAG R.Arr O Magnitude array (Optional)
1947  ! DIR R.Arr O Direction array (degrees) (Optional)
1948  ! TOLERANCE Real I Minimum allowed magnitude (Optional)
1949  ! CONV Char I Ouput direciton convention (Optional)
1950  ! ----------------------------------------------------------------
1951  !
1952  ! 3. Remarks
1953  !
1954  ! Optional CONV specifies direction convention. Must be one of:
1955  ! 'N'=Nautical : North=0, clockwise, direction-from (default)
1956  ! 'O'=Oceangraphic : North=0, clockwise, direction-to
1957  ! 'C'=Cartesian : North=90, counter-clockwise, direction-to
1958  !
1959  !/ ------------------------------------------------------------------- /
1960  USE constants, ONLY: rade, undef
1961  REAL, INTENT(INOUT) :: U(NSEA), V(NSEA)
1962  INTEGER, INTENT(IN) :: NSEA
1963  REAL, INTENT(OUT), OPTIONAL :: MAG(NSEA), DIR(NSEA)
1964  REAL, INTENT(IN), OPTIONAL :: TOLERANCE
1965  CHARACTER, INTENT(IN), OPTIONAL :: CONV
1966  !/ ------------------------------------------------------------------- /
1967  !/ Local parameters
1968  !
1969  REAL :: TOL, SGN, OFFSET, TMP
1970  CHARACTER :: DIRCONV
1971  INTEGER :: ISEA
1972  LOGICAL :: INPLACE
1973 
1974  dirconv = 'N'
1975  tol = 1.0
1976  inplace = .true.
1977  IF(PRESENT(tolerance)) tol = tolerance
1978  IF(PRESENT(conv)) dirconv = conv
1979  IF(PRESENT(mag) .AND. PRESENT(dir)) inplace = .false.
1980 
1981  SELECT CASE (conv)
1982  CASE('N')
1983  offset = 630.
1984  sgn = -1.
1985  CASE('O')
1986  offset = 450.
1987  sgn = -1.
1988  CASE('C')
1989  offset = 360.
1990  sgn = 1.
1991  CASE DEFAULT
1992  WRITE(*,*) "UV_TO_MAG_DIR: UNKNOWN DIR CONVENTION: ", dirconv
1993  CALL extcde(1)
1994  END SELECT
1995 
1996  IF(inplace) THEN
1997  DO isea=1, nsea
1998  tmp = sqrt(u(isea)**2 + v(isea)**2)
1999  IF(tmp .GE. tol) THEN
2000  v(isea) = mod(offset + (sgn * rade * atan2(v(isea), u(isea))), 360.)
2001  u(isea) = tmp
2002  ELSE
2003  u(isea) = undef
2004  v(isea) = undef
2005  END IF
2006  END DO
2007  ELSE
2008  DO isea=1, nsea
2009  mag(isea) = sqrt(u(isea)**2 + v(isea)**2)
2010  IF(mag(isea) .GE. tol) THEN
2011  dir(isea) = mod(offset + (sgn * rade * atan2(v(isea), u(isea))), 360.)
2012  ELSE
2013  mag(isea) = undef
2014  dir(isea) = undef
2015  END IF
2016  END DO
2017  ENDIF
2018 
2019  END SUBROUTINE uv_to_mag_dir
2020 
2021  !========================================================================
2031 
2032  subroutine print_memcheck(iun, msg)
2033 #ifdef W3_MEMCHECK
2034  USE mallocinfo_m
2035 #endif
2036  integer , intent(in) :: iun
2037  character(len=*) , intent(in) :: msg
2038 
2039 #ifdef W3_MEMCHECK
2040  ! local variables
2041  type(mallinfo_t) :: mallinfos
2042 
2043  write(iun,*) trim(msg)
2044  call getmallocinfo(mallinfos)
2045  call printmallinfo(iun, mallinfos)
2046 #endif
2047  end subroutine print_memcheck
2048  !/
2049  !/ End of module W3SERVMD -------------------------------------------- /
2050  !/
2051 END MODULE w3servmd
constants::pi
real, parameter pi
PI Value of Pi.
Definition: constants.F90:71
w3servmd::nextln
subroutine nextln(CHCKC, NDSI, NDSE)
Definition: w3servmd.F90:222
include
cmake src_list cmake include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_switches.cmake) check_switches("$
Definition: CMakeLists.txt:15
rotate
subroutine rotate(X1, X2)
Definition: w3servmd.F90:1912
w3servmd::ej5p
real function ej5p(F, ALFA, FP, YLN, SIGA, SIGB)
Definition: w3servmd.F90:407
mallocinfo_m::printmallinfo
subroutine printmallinfo(ihdnl, malinfo)
Definition: w3meminfo.F90:177
constants::dera
real, parameter dera
DERA Conversion factor from degrees to radians.
Definition: constants.F90:77
mallocinfo_m::getmallocinfo
subroutine getmallocinfo(malinfo)
Definition: w3meminfo.F90:107
mallocinfo_m
Definition: w3meminfo.F90:1
constants::rade
real, parameter rade
RADE Conversion factor from radians to degrees.
Definition: constants.F90:76
w3servmd::strsplit
subroutine strsplit(STRING, TAB)
Definition: w3servmd.F90:1440
w3servmd::w3eqtoll
subroutine w3eqtoll(PHI_EQ, LAMBDA_EQ, PHI, LAMBDA, ANGLED, PHI_POLE, LAMBDA_POLE, POINTS)
Definition: w3servmd.F90:1224
w3servmd::w3acturn
subroutine w3acturn(NDirc, NFreq, Alpha, Spectr)
Definition: w3servmd.F90:977
w3servmd::wwtime
subroutine wwtime(STRNG)
Definition: w3servmd.F90:664
w3servmd::w3thrtn
subroutine w3thrtn(NSEA, THETA, AnglD, Degrees)
Definition: w3servmd.F90:1333
w3servmd
Definition: w3servmd.F90:3
w3servmd::w3lltoeq
subroutine w3lltoeq(PHI, LAMBDA, PHI_EQ, LAMBDA_EQ, ANGLED, PHI_POLE, LAMBDA_POLE, POINTS)
Definition: w3servmd.F90:1084
w3servmd::print_memcheck
subroutine print_memcheck(iun, msg)
Write memory statistics if requested.
Definition: w3servmd.F90:2033
w3servmd::ssort1
subroutine ssort1(X, Y, N, KFLAG)
Definition: w3servmd.F90:1518
w3servmd::diagonalize
subroutine diagonalize(a1, d, v, nrot)
Definition: w3servmd.F90:1840
w3servmd::str_to_upper
subroutine str_to_upper(STR)
Definition: w3servmd.F90:1500
constants::tpi
real, parameter tpi
TPI 2*Pi.
Definition: constants.F90:72
w3servmd::strace
subroutine strace(IENT, SNAME)
Definition: w3servmd.F90:148
w3servmd::wwdate
subroutine wwdate(STRNG)
Definition: w3servmd.F90:595
mallocinfo_m::mallinfo_t
This structure type is used to return information about the dynamic memory allocator.
Definition: w3meminfo.F90:60
constants
Define some much-used constants for global use (all defined as PARAMETER).
Definition: constants.F90:20
w3servmd::w3xyrtn
subroutine w3xyrtn(NSEA, XVEC, YVEC, AnglD)
Definition: w3servmd.F90:1387
w3servmd::extcde
subroutine extcde(IEXIT, UNIT, MSG, FILE, LINE, COMM)
Definition: w3servmd.F90:736
w3servmd::itrace
subroutine itrace(NDS, NMAX)
Definition: w3servmd.F90:91
constants::undef
real undef
UNDEF Value for undefined variable in output.
Definition: constants.F90:84
w3servmd::w3spectn
subroutine w3spectn(NFreq, NDirc, Alpha, Spectr)
Definition: w3servmd.F90:889
w3servmd::w3s2xy
subroutine w3s2xy(NSEA, MSEA, MX, MY, S, MAPSF, XY)
Definition: w3servmd.F90:337
w3servmd::dist_sphere
real function dist_sphere(lo1, la1, lo2, la2)
Definition: w3servmd.F90:516
w3servmd::uv_to_mag_dir
subroutine uv_to_mag_dir(U, V, NSEA, MAG, DIR, TOLERANCE, CONV)
Definition: w3servmd.F90:1922