1module horizontalCoord_mod
2 ! MODULE horizontalCoord_mod (prefix='hco' category='7. Low-level data objects')
3 !
4 !:Purpose: Derived type and procedures related to the horizontal grid
5 ! coordinate for various grids (global and limited area).
6 !
7 use midasMpi_mod
8 use earthConstants_mod
9 use mathPhysConstants_mod
10 use utilities_mod
11 use varNameList_mod
12 use physicsFunctions_mod
13
14 implicit none
15 save
16 private
17
18 ! Public derived type
19 public :: struct_hco
20
21 ! Public Subroutines
22 public :: hco_SetupFromFile, hco_equal, hco_deallocate, hco_mpiBcast, hco_weight, hco_setupYgrid
23
24 integer, parameter :: maxNumSubGrid = 2
25
26 type :: struct_hco
27 character(len=32) :: gridname
28 logical :: initialized = .false.
29 integer :: ni
30 integer :: nj
31 character(len=1) :: grtyp
32 character(len=1) :: grtypTicTac
33 integer :: ig1
34 integer :: ig2
35 integer :: ig3
36 integer :: ig4
37 integer :: EZscintID = -1
38 integer :: numSubGrid
39 integer :: EZscintIDsubGrids(maxNumSubGrid)
40 real(8), allocatable :: lat(:) ! in radians
41 real(8), allocatable :: lon(:) ! in radians
42 real(4), allocatable :: lat2d_4(:,:) ! in radians
43 real(4), allocatable :: lon2d_4(:,:) ! in radians
44 real(8) :: dlat ! in radians
45 real(8) :: dlon ! in radians
46 real(8) :: maxGridSpacing ! in meter
47 real(8) :: minGridSpacing ! in meter
48 logical :: global
49 logical :: rotated
50 real(8) :: xlat1, xlat1_yan
51 real(8) :: xlon1, xlon1_yan
52 real(8) :: xlat2, xlat2_yan
53 real(8) :: xlon2, xlon2_yan
54 real(4), allocatable :: tictacU(:)
55 end type struct_hco
56
57contains
58
59 !--------------------------------------------------------------------------
60 ! hco_SetupFromFile
61 !--------------------------------------------------------------------------
62 subroutine hco_SetupFromFile(hco, TemplateFile, EtiketName, GridName_opt, &
63 varName_opt)
64 !
65 !:Purpose: to initialize hco structure from a template file
66 !
67 implicit none
68
69 ! Arguments:
70 type(struct_hco), pointer, intent(out) :: hco
71 character(len=*), intent(in) :: TemplateFile
72 character(len=*), intent(in) :: EtiketName
73 character(len=*), optional, intent(in) :: GridName_opt
74 character(len=*), optional, intent(in) :: varName_opt
75
76 ! Locals:
77 real(8), allocatable :: lat_8(:)
78 real(8), allocatable :: lon_8(:)
79 real(8) :: maxDeltaLat, maxDeltaLon, maxGridSpacing, deltaLon, deltaLat
80 real(8) :: minDeltaLat, minDeltaLon, minGridSpacing
81 real(8) :: deltaLon1, deltaLon2, deltaLon3
82 real(8) :: deltaLat1, deltaLat2, deltaLat3
83 real(8), save :: maxGridSpacingPrevious = -1.0d0
84 real(8), save :: minGridSpacingPrevious = -1.0d0
85 real(4) :: xlat1_4, xlon1_4, xlat2_4, xlon2_4
86 real(4) :: xlat1_yan_4, xlon1_yan_4, xlat2_yan_4, xlon2_yan_4
87 integer :: iu_template, numSubGrid, varIndex
88 integer :: fnom, fstlir, fstouv, fstfrm, fclos
89 integer :: ezqkdef, ezget_nsubgrids, ezget_subgridids, ezgprm
90 integer :: key, fstinf, fstprm, ier, EZscintID, EZscintIDsubGrids(maxNumSubGrid)
91 integer :: ni, nj, ni_tictacU, ni_t, nj_t, nlev_t, gdll
92 integer :: dateo, deet, npas, nk, nbits, datyp
93 integer :: ip1, ip2, ip3, swa, lng, dltf, ubc
94 integer :: extra1, extra2, extra3
95 integer :: ig1, ig2, ig3, ig4
96 integer :: ig1_tictac, ig2_tictac, ig3_tictac, ig4_tictac
97 integer :: ni_yy, nj_yy, ig1_yy, ig2_yy, ig3_yy, ig4_yy
98 integer :: latIndex, lonIndex, latIndexBeg, latIndexEnd
99 real(4), parameter :: absMaxLat = 85. ! abs of latitude threshold where to compute minGridSpacing in 3.2
100 logical :: FileExist, global, rotated, foundVarNameInFile
101 character(len=4 ) :: nomvar
102 character(len=2 ) :: typvar
103 character(len=1 ) :: grtyp, grtypTicTac
104 character(len=12) :: etiket
105
106 if(.not.associated(hco)) then
107 allocate(hco)
108 else
109 call utl_abort('hco_setupFromFile: supplied hco must be null')
110 end if
111
112 !
113 !- 1.1 Determine which variable to use for defining the grid
114 !
115 if (present(varName_opt)) then
116
117 ! User specified variable name
118 nomvar = varName_opt
119
120 else
121
122 ! First try to use P0
123 nomvar = 'P0'
124
125 if (.not. utl_varNamePresentInFile(nomvar,fileName_opt=trim(TemplateFile))) then
126 ! P0 not present, look for another suitable variable in the file
127
128 foundVarNameInFile = .false.
129 do varIndex = 1, vnl_numvarmax
130 nomvar = vnl_varNameList(varIndex)
131
132 ! check if variable is in the file
133 if (.not. utl_varNamePresentInFile(nomvar,fileName_opt=trim(TemplateFile))) cycle
134
135 foundVarNameInFile = .true.
136 exit
137
138 end do
139
140 if (.not. foundVarNameInFile) call utl_abort('hco_SetupFromFile: NO variables found in the file!!!')
141
142 end if
143
144 end if
145
146 write(*,*) 'hco_SetupFromFile: defining hco by varname= ', nomvar
147
148
149 !
150 !- 1.2 Open/Check template file
151 !
152 inquire(file=trim(TemplateFile), exist=FileExist)
153
154 if (FileExist) then
155 iu_template = 0
156 ier = fnom(iu_template,trim(TemplateFile),'RND+OLD+R/O',0)
157 if (ier == 0) then
158 write(*,*)
159 write(*,*) 'hco_setupFromFile: Template File =', trim(TemplateFile)
160 ier = fstouv(iu_template,'RND+OLD')
161 else
162 write(*,*)
163 write(*,*) 'hco_SetupFromFile: Error in opening the template grid file'
164 write(*,*) trim(TemplateFile)
165 call utl_abort('hco_SetupFromFile')
166 end if
167 else
168 write(*,*)
169 write(*,*) 'hco_SetupFromFile: template grid file DOES NOT EXIST'
170 write(*,*) trim(TemplateFile)
171 call utl_abort('hco_SetupFromFile')
172 end if
173
174 !
175 !- 2. Get Horizontal grid info
176 !
177
178 !- 2.1 Grid size and grid projection info
179 dateo = -1
180 etiket = EtiketName
181 ip1 = -1
182 ip2 = -1
183 ip3 = -1
184 typvar = ' '
185
186 key = fstinf(iu_template, & ! IN
187 ni, nj, nk, & ! OUT
188 dateo, etiket, ip1, ip2, ip3, typvar, nomvar)! IN
189
190 if (key < 0) then
191 write(*,*)
192 write(*,*) 'hco_SetupFromFile: Unable to find output horiz grid info using = ',nomvar
193 write(*,*) ' with etiket = ',trim(EtiketName)
194 call utl_abort('hco_setupFromFile: unable to setup the structure')
195 end if
196
197 ier = fstprm(key, & ! IN
198 dateo, deet, npas, ni, nj, nk, nbits, & ! OUT
199 datyp, ip1, ip2, ip3, typvar, nomvar, etiket, & ! OUT
200 grtyp, ig1, ig2, ig3, & ! OUT
201 ig4, swa, lng, dltf, ubc, extra1, extra2, extra3) ! OUT
202
203 if (trim(grtyp) == 'G' .and. ig2 == 1) then
204 call utl_abort('hco_setupFromFile: ERROR: due to bug in ezsint, Gaussian grid with ig2=1 no longer supported')
205 end if
206
207 EZscintID = ezqkdef(ni, nj, grtyp, ig1, ig2, ig3, ig4, iu_template) ! IN
208 numSubGrid = 1
209 EZscintIDsubGrids(:) = MPC_missingValue_INT
210
211 allocate(lat_8(1:nj))
212 allocate(lon_8(1:ni))
213
214 allocate(hco%lat2d_4(1:ni,1:nj))
215 allocate(hco%lon2d_4(1:ni,1:nj))
216
217 ier = gdll(EZscintID, & ! IN
218 hco%lat2d_4, hco%lon2d_4) ! OUT
219
220 xlat1_yan_4 = MPC_missingValue_R4
221 xlon1_yan_4 = MPC_missingValue_R4
222 xlat2_yan_4 = MPC_missingValue_R4
223 xlon2_yan_4 = MPC_missingValue_R4
224
225 grtypTicTac = 'X'
226
227 if (mmpi_myid == 0) write(*,*) 'hco_setupFromFile: grtyp, ni, nj, EZscintID = ', grtyp, ni, nj, EZscintID
228
229 !- 2.2 Rotated lat-lon grid
230 if (trim(grtyp) == 'Z') then
231
232 !- 2.2.1 Read the Longitudes
233 dateo = -1
234 etiket = ''
235 ip1 = ig1
236 ip2 = ig2
237 ip3 = ig3
238 typvar = ''
239 nomvar = '>>'
240
241 ier = utl_fstlir(lon_8, & ! OUT
242 iu_template, & ! IN
243 ni_t, nj_t, nlev_t, & ! OUT
244 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
245
246 if (ier < 0) then
247 write(*,*)
248 write(*,*) 'hco_SetupFromFile: Unable to find >> grid descriptors'
249 call utl_abort('hco_setupFromFile')
250 end if
251
252 ! Test if the dimensions are compatible with the grid
253 if (ni_t /= ni .or. nj_t /= 1) then
254 write(*,*)
255 write(*,*) 'hco_SetupFromFile: Incompatible >> grid descriptors !'
256 write(*,*) 'Found :', ni_t, nj_t
257 write(*,*) 'Should be :', ni, 1
258 call utl_abort('hco_setupFromFile')
259 end if
260
261 !- 2.2.2 Read the latitudes
262 dateo = -1
263 etiket = ''
264 ip1 = ig1
265 ip2 = ig2
266 ip3 = ig3
267 typvar = ''
268 nomvar = '^^'
269
270 ier = utl_fstlir(lat_8, & ! OUT
271 iu_template, & ! IN
272 ni_t, nj_t, nlev_t, & ! OUT
273 dateo, etiket, ip1, ip2, ip3, typvar,nomvar) ! IN
274
275 if (ier < 0) then
276 write(*,*)
277 write(*,*) 'hco_SetupFromFile: Unable to find ^^ grid descriptors'
278 call utl_abort('hco_setupFromFile')
279 end if
280
281 ! Test if the dimensions are compatible with the grid
282 if (ni_t /= 1 .or. nj_t /= nj) then
283 write(*,*)
284 write(*,*) 'hco_SetupFromFile: Incompatible ^^ grid descriptors !'
285 write(*,*) 'Found :', ni_t, nj_t
286 write(*,*) 'Should be :', 1, nj
287 call utl_abort('hco_setupFromFile')
288 end if
289
290 !- 2.2.3 Do we have a rotated grid ?
291 dateo = -1
292 etiket = ''
293 ip1 = ig1
294 ip2 = ig2
295 ip3 = ig3
296 typvar = ''
297 nomvar = '^^'
298
299 key = fstinf(iu_template, & ! IN
300 ni_t, nj_t, nk, & ! OUT
301 dateo, etiket, ip1, ip2, ip3, typvar, nomvar) ! IN
302
303 ier = fstprm(key, & ! IN
304 dateo, deet, npas, ni_t, nj_t, nk, nbits, & ! OUT
305 datyp, ip1, ip2, ip3, typvar, nomvar, etiket, & ! OUT
306 grtypTicTac, ig1_tictac, ig2_tictac, & ! OUT
307 ig3_tictac, ig4_tictac, swa, lng, dltf, & ! OUT
308 ubc, extra1, extra2, extra3) ! OUT
309
310 call cigaxg (grtypTicTac, & ! IN
311 xlat1_4, xlon1_4, xlat2_4, xlon2_4, & ! OUT
312 ig1_tictac, ig2_tictac, ig3_tictac, ig4_tictac) ! IN
313
314 if (xlat1_4 == 0.0 .and. xlat2_4 == 0.0) then
315 rotated = .false.
316 else
317 rotated = .true.
318 end if
319 if (mmpi_myid == 0) then
320 write(*,*) 'hco_setupFromFile: xlat1/2, xlon1/2, rotated = ', &
321 xlat1_4, xlat2_4, xlon1_4, xlon2_4, rotated
322 end if
323
324 !- 2.2.4 Is this a global or a LAM domain ?
325 call global_or_lam(global, & ! OUT
326 lon_8, ni) ! IN
327
328 !- 2.3 B Grid
329 else if (trim(grtyp) == 'B') then
330
331 !- 2.3.1 Find the latitudes and longitudes
332 lon_8(:) = real(hco%lon2d_4(:,nj/2),8)
333 lat_8(:) = real(hco%lat2d_4(1,:),8)
334
335 !- 2.3.2 This grid type is not rotated
336 rotated = .false.
337 xlat1_4 = 0.0
338 xlon1_4 = 180.0
339 xlat2_4 = 0.0
340 xlon2_4 = 180.0
341
342 !- 2.3.3 We know this is a global grid
343 global = .true.
344
345 !- 2.4 Gaussian Grid
346 else if (trim(grtyp) == 'G') then
347
348 !- 2.4.1 Find the latitudes and longitudes
349 lon_8(:) = real(hco%lon2d_4(:,nj/2),8)
350 lat_8(:) = real(hco%lat2d_4(1,:),8)
351
352 !- 2.4.2 This grid type is not rotated
353 rotated = .false.
354 xlat1_4 = 0.0
355 xlon1_4 = 180.0
356 xlat2_4 = 0.0
357 xlon2_4 = 180.0
358
359 !- 2.4.3 We know this is a global grid
360 global = .true.
361
362 !- 2.5 Universal Grid (Yin-Yang) - not fully supported: use at own risk!
363 else if (trim(grtyp) == 'U') then
364
365 !- 2.5.1 Read the tic-tac vector
366 dateo = -1
367 etiket = ' '
368 ip1 = ig1
369 ip2 = ig2
370 ip3 = ig3
371 typvar = 'X'
372 nomvar = '^>'
373
374 ni_tictacU = 5 + 2 * (10 + ni + nj/2)
375 allocate(hco%tictacU(ni_tictacU))
376 ier = fstlir(hco%tictacU, & ! OUT
377 iu_template, & ! IN
378 ni_t, nj_t, nlev_t, & ! OUT
379 dateo, etiket, ip1, ip2, ip3, typvar, nomvar) ! IN
380
381 if (ier < 0) then
382 write(*,*)
383 write(*,*) 'hco_SetupFromFile: Unable to find ^> grid descriptors'
384 call utl_abort('hco_setupFromFile')
385 end if
386
387 ! Test if the dimensions are compatible with the grid
388 if (ni_t /= ni_tictacU .or. nj_t /= 1) then
389 write(*,*)
390 write(*,*) 'hco_SetupFromFile: Incompatible ^> grid descriptors !'
391 write(*,*) 'Found :', ni_t, nj_t
392 write(*,*) 'Should be :', ni_tictacU, 1
393 call utl_abort('hco_setupFromFile')
394 end if
395
396 !- 2.5.1 Initialize latitudes and longitudes to dummy values - should not be used!
397 lon_8(:) = MPC_missingValue_R8
398 lat_8(:) = MPC_missingValue_R8
399
400 !- 2.5.2 Yin-Yan subgrid IDs
401 numSubGrid = ezget_nsubgrids(EZscintID)
402 if (numSubGrid /= 2) then
403 call utl_abort('hco_setupFromFile: CONFUSED! number of sub grids must be 2')
404 end if
405 ier = ezget_subgridids(EZscintID, EZscintIDsubGrids)
406
407 !- 2.5.3 Determine parameters related to Yin and Yan grid rotations
408 rotated = .true. ! since Yin-Yan is made up of 2 grids with different rotations
409
410 ier = ezgprm(EZscintIDsubGrids(1), grtypTicTac, ni_yy, nj_yy, ig1_yy, ig2_yy, ig3_yy, ig4_yy)
411 grtypTicTac = 'E' ! needed since ezgprm returns 'Z', but grtyp for tictac should be 'E'
412 call cigaxg (grtypTicTac, & ! IN
413 xlat1_4, xlon1_4, xlat2_4, xlon2_4, & ! OUT
414 ig1_yy, ig2_yy, ig3_yy, ig4_yy) ! IN
415
416 ier = ezgprm(EZscintIDsubGrids(2), grtypTicTac, ni_yy, nj_yy, ig1_yy, ig2_yy, ig3_yy, ig4_yy)
417 grtypTicTac = 'E' ! needed since ezgprm returns 'Z', but grtyp for tictac should be 'E'
418 call cigaxg (grtypTicTac, & ! IN
419 xlat1_yan_4, xlon1_yan_4, xlat2_yan_4, xlon2_yan_4, & ! OUT
420 ig1_yy, ig2_yy, ig3_yy, ig4_yy) ! IN
421
422 rotated = .true. ! since Yin-Yan is made up of 2 grids with different rotations
423
424 !- 2.5.3 We know this is a global grid
425 global = .true.
426
427 !- 2.5 Irregular structure
428 else if (trim(grtyp) == 'Y') then
429
430 !- 2.6.1 This grid type is not rotated
431 rotated = .false.
432 xlat1_4 = 0.0
433 xlon1_4 = 0.0
434 xlat2_4 = 1.0
435 xlon2_4 = 1.0
436
437 grtypTicTac = 'L'
438
439 !- 2.6.2 Test using first row of longitudes (should work for ORCA grids)
440 lon_8(:) = hco%lon2d_4(:,1)
441 call global_or_lam(global, & ! OUT
442 lon_8, ni) ! IN
443
444 !- 2.6.3 Initialize latitudes and longitudes to dummy values - should not be used!
445 lon_8(:) = MPC_missingValue_R8
446 lat_8(:) = MPC_missingValue_R8
447
448 else
449 write(*,*)
450 write(*,*) 'hco_SetupFromFile: Only grtyp = Z or G or B or U or Y are supported !, grtyp = ', trim(grtyp)
451 call utl_abort('hco_setupFromFile')
452 end if
453
454 !
455 !- 3. Initialized Horizontal Grid Structure
456 !
457 allocate(hco%lat(1:nj))
458 allocate(hco%lon(1:ni))
459
460 if (present(gridName_opt)) then
461 hco%gridname = trim(gridName_opt)
462 else
463 hco%gridname = 'UNDEFINED'
464 end if
465 hco%ni = ni
466 hco%nj = nj
467 hco%grtyp = trim(grtyp)
468 hco%grtypTicTac = trim(grtypTicTac)
469 hco%ig1 = ig1
470 hco%ig2 = ig2
471 hco%ig3 = ig3
472 hco%ig4 = ig4
473 hco%EZscintID = EZscintID
474 hco%numSubGrid = numSubGrid
475 hco%EZscintIDsubGrids(:) = EZscintIDsubGrids(:)
476 hco%lon(:) = lon_8(:) * MPC_RADIANS_PER_DEGREE_R8
477 hco%lat(:) = lat_8(:) * MPC_RADIANS_PER_DEGREE_R8
478 hco%dlon = (lon_8(2) - lon_8(1)) * MPC_RADIANS_PER_DEGREE_R8
479 hco%dlat = (lat_8(2) - lat_8(1)) * MPC_RADIANS_PER_DEGREE_R8
480 hco%global = global
481 hco%rotated = rotated
482 hco%xlat1 = real(xlat1_4,8)
483 hco%xlon1 = real(xlon1_4,8)
484 hco%xlat2 = real(xlat2_4,8)
485 hco%xlon2 = real(xlon2_4,8)
486 hco%xlat1_yan = real(xlat1_yan_4,8)
487 hco%xlon1_yan = real(xlon1_yan_4,8)
488 hco%xlat2_yan = real(xlat2_yan_4,8)
489 hco%xlon2_yan = real(xlon2_yan_4,8)
490 hco%initialized = .true.
491
492 hco%lat2d_4(:,:) = hco%lat2d_4(:,:) * MPC_RADIANS_PER_DEGREE_R8
493 hco%lon2d_4(:,:) = hco%lon2d_4(:,:) * MPC_RADIANS_PER_DEGREE_R8
494
495 deallocate(lat_8)
496 deallocate(lon_8)
497
498 !- 3.1 Compute maxGridSpacing
499
500 latIndexBeg = 1
501 if (trim(grtyp) == 'U') then
502 latIndexEnd = nj / 2
503 else
504 latIndexEnd = nj
505 end if
506
507 maxDeltaLat = 0.0d0
508 do lonIndex = 1, ni - 1
509 do latIndex = latIndexBeg, latIndexEnd - 1
510
511 deltaLat1 = abs(hco%lat2d_4(lonIndex, latIndex) - hco%lat2d_4(lonIndex , latIndex + 1))
512 deltaLat2 = abs(hco%lat2d_4(lonIndex, latIndex) - hco%lat2d_4(lonIndex + 1, latIndex ))
513 deltaLat3 = abs(hco%lat2d_4(lonIndex, latIndex) - hco%lat2d_4(lonIndex + 1, latIndex + 1))
514
515 deltaLat = max(deltaLat1, deltaLat2, deltaLat3)
516 if (deltaLat > maxDeltaLat) maxDeltaLat = deltaLat
517
518 end do
519 end do
520
521 maxDeltaLon = 0.0d0
522 do lonIndex = 1, ni - 1
523 do latIndex = latIndexBeg, latIndexEnd - 1
524
525 deltaLon1 = abs(hco%lon2d_4(lonIndex, latIndex) - hco%lon2d_4(lonIndex , latIndex + 1))
526 deltaLon2 = abs(hco%lon2d_4(lonIndex, latIndex) - hco%lon2d_4(lonIndex + 1, latIndex ))
527 deltaLon3 = abs(hco%lon2d_4(lonIndex, latIndex) - hco%lon2d_4(lonIndex + 1, latIndex + 1))
528
529 if (deltaLon1 > MPC_PI_R8) deltaLon1 = deltaLon1 - 2.0d0 * MPC_PI_R8
530 deltaLon1 = abs(deltaLon1 * cos(hco%lat2d_4(lonIndex,latIndex)))
531 if (deltaLon2 > MPC_PI_R8) deltaLon2 = deltaLon2 - 2.0d0 * MPC_PI_R8
532 deltaLon2 = abs(deltaLon2 * cos(hco%lat2d_4(lonIndex,latIndex)))
533 if (deltaLon3 > MPC_PI_R8) deltaLon3 = deltaLon3 - 2.0d0 * MPC_PI_R8
534 deltaLon3 = abs(deltaLon3 * cos(hco%lat2d_4(lonIndex,latIndex)))
535
536 deltaLon = max(deltaLon1, deltaLon2, deltaLon3)
537 if (deltaLon > maxDeltaLon) maxDeltaLon = deltaLon
538
539 end do
540 end do
541
542 maxGridSpacing = ec_ra * sqrt(2.0d0) * max(maxDeltaLon, maxDeltaLat)
543
544 if (mmpi_myid == 0 .and. maxGridSpacing /= maxGridSpacingPrevious) then
545 maxGridSpacingPrevious = maxGridSpacing
546 write(*,*) 'hco_setupFromFile: maxDeltaLat=', maxDeltaLat * MPC_DEGREES_PER_RADIAN_R8, ' deg'
547 write(*,*) 'hco_setupFromFile: maxDeltaLon=', maxDeltaLon * MPC_DEGREES_PER_RADIAN_R8, ' deg'
548 write(*,*) 'hco_setupFromFile: maxGridSpacing=', maxGridSpacing, ' m'
549 end if
550
551 if (maxGridSpacing > 1.0d6) then
552 call utl_abort('hco_setupFromFile: maxGridSpacing is greater than 1000 km.')
553 end if
554
555 hco%maxGridSpacing = maxGridSpacing
556
557 !- 3.2 Compute minGridSpacing
558
559 minDeltaLat = 1.0d6
560 do lonIndex = 1, ni - 1
561 do latIndex = latIndexBeg, latIndexEnd - 1
562
563 deltaLat1 = abs(hco%lat2d_4(lonIndex, latIndex) - hco%lat2d_4(lonIndex , latIndex + 1))
564 deltaLat2 = abs(hco%lat2d_4(lonIndex, latIndex) - hco%lat2d_4(lonIndex + 1, latIndex ))
565 deltaLat3 = abs(hco%lat2d_4(lonIndex, latIndex) - hco%lat2d_4(lonIndex + 1, latIndex + 1))
566
567 deltaLat = max(deltaLat1, deltaLat2, deltaLat3)
568 if (deltaLat < minDeltaLat) minDeltaLat = deltaLat
569
570 end do
571 end do
572
573 minDeltaLon = 1.0d6
574 do lonIndex = 1, ni - 1
575 do latIndex = latIndexBeg, latIndexEnd - 1
576
577 if(abs(hco%lat2d_4(lonIndex, latIndex)) * MPC_DEGREES_PER_RADIAN_R8 < absMaxLat) then
578
579 deltaLon1 = abs(hco%lon2d_4(lonIndex, latIndex) - hco%lon2d_4(lonIndex , latIndex + 1))
580 deltaLon2 = abs(hco%lon2d_4(lonIndex, latIndex) - hco%lon2d_4(lonIndex + 1, latIndex ))
581 deltaLon3 = abs(hco%lon2d_4(lonIndex, latIndex) - hco%lon2d_4(lonIndex + 1, latIndex + 1))
582
583 if (deltaLon1 > MPC_PI_R8) deltaLon1 = deltaLon1 - 2.0d0 * MPC_PI_R8
584 deltaLon1 = abs(deltaLon1 * cos(hco%lat2d_4(lonIndex,latIndex)))
585 if (deltaLon2 > MPC_PI_R8) deltaLon2 = deltaLon2 - 2.0d0 * MPC_PI_R8
586 deltaLon2 = abs(deltaLon2 * cos(hco%lat2d_4(lonIndex,latIndex)))
587 if (deltaLon3 > MPC_PI_R8) deltaLon3 = deltaLon3 - 2.0d0 * MPC_PI_R8
588 deltaLon3 = abs(deltaLon3 * cos(hco%lat2d_4(lonIndex,latIndex)))
589
590 deltaLon = max(deltaLon1, deltaLon2, deltaLon3)
591 if (deltaLon < minDeltaLon) minDeltaLon = deltaLon
592
593 end if
594
595 end do
596 end do
597
598 minGridSpacing = ec_ra * sqrt(2.0d0) * min(minDeltaLon, minDeltaLat)
599
600 if (mmpi_myid == 0 .and. minGridSpacing /= minGridSpacingPrevious) then
601 minGridSpacingPrevious = minGridSpacing
602 write(*,*) 'hco_setupFromFile: minDeltaLat=', minDeltaLat * MPC_DEGREES_PER_RADIAN_R8, ' deg'
603 write(*,*) 'hco_setupFromFile: minDeltaLon=', minDeltaLon * MPC_DEGREES_PER_RADIAN_R8, ' deg'
604 write(*,*) 'hco_setupFromFile: minGridSpacing=', minGridSpacing, ' m'
605 end if
606
607 if (minGridSpacing > 1.0d6) then
608 call utl_abort('hco_setupFromFile: minGridSpacing is greater than 1000 km.')
609 end if
610
611 hco%minGridSpacing = minGridSpacing
612
613 !
614 !- 4. Close the input file
615 !
616 ier = fstfrm(iu_template)
617 ier = fclos (iu_template)
618
619 end subroutine hco_SetupFromFile
620
621 !--------------------------------------------------------------------------
622 ! Global_or_lam
623 !--------------------------------------------------------------------------
624 subroutine global_or_lam(global, lon, ni)
625 !
626 !:Purpose: to decide if a given grid is global or lam from input longitude array
627 !
628 implicit none
629
630 ! Arguments:
631 integer, intent(in) :: ni
632 real(8), intent(in) :: lon(ni)
633 logical, intent(out) :: global
634
635 ! Locals:
636 real(8) :: dx, next_lon
637
638 dx = lon(2) - lon(1)
639 next_lon = lon(ni) + 1.5d0 * dx
640
641 write(*,*)
642 write(*,*) 'dx = ',dx
643 write(*,*) 'lon(ni) = ',lon(ni)
644 write(*,*) 'next_lon = ',next_lon
645 write(*,*) 'lon(1) = ',lon(1)
646
647 if (next_lon - lon(1) > 360.0d0 .or. &
648 next_lon - lon(1) < 3.0*dx) then
649
650 global = .true.
651 if (lon(1) == lon(ni)) then
652 write(*,*)
653 write(*,*) ' *** Global Grid where i = ni (repetition) '
654 else
655 write(*,*)
656 write(*,*) ' *** Global Grid where i /= ni '
657 end if
658
659 else
660
661 global = .false.
662 write(*,*)
663 write(*,*) ' *** Limited-Area Grid '
664
665 end if
666
667 end subroutine global_or_lam
668
669 !--------------------------------------------------------------------------
670 ! mpiBcast
671 !--------------------------------------------------------------------------
672 subroutine hco_mpiBcast(hco)
673 !
674 !:Purpose: to broadcast hco strucure from MPI task 0 to other tasks
675 !
676 implicit none
677
678 ! Arguments:
679 type(struct_hco), pointer, intent(inout) :: hco
680
681 ! Locals:
682 integer :: ierr
683 integer, external :: ezqkdef
684
685 write(*,*) 'hco_mpiBcast: starting'
686
687 if (mmpi_myid > 0) then
688 if(.not.associated(hco)) then
689 allocate(hco)
690 else
691 call utl_abort('hco_mpiBcast: hco must be nullified for mpi task id > 0')
692 end if
693 end if
694
695 call rpn_comm_bcastc(hco%gridname, len(hco%gridname), 'MPI_CHARACTER', 0, 'GRID', ierr)
696 call rpn_comm_bcast(hco%initialized, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
697 call rpn_comm_bcast(hco%ni, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
698 call rpn_comm_bcast(hco%nj, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
699 call rpn_comm_bcastc(hco%grtyp, len(hco%grtyp), 'MPI_CHARACTER', 0, 'GRID', ierr)
700 call rpn_comm_bcastc(hco%grtypTicTac, len(hco%grtypTicTac), 'MPI_CHARACTER', 0, 'GRID', ierr)
701 call rpn_comm_bcast(hco%ig1, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
702 call rpn_comm_bcast(hco%ig2, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
703 call rpn_comm_bcast(hco%ig3, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
704 call rpn_comm_bcast(hco%ig4, 1, 'MPI_INTEGER', 0, 'GRID', ierr)
705 if (mmpi_myid > 0) then
706 allocate(hco%lat(hco%nj))
707 allocate(hco%lon(hco%ni))
708 allocate(hco%lat2d_4(hco%ni,hco%nj))
709 allocate(hco%lon2d_4(hco%ni,hco%nj))
710 end if
711 call rpn_comm_bcast(hco%lat, size(hco%lat), 'MPI_REAL8', 0, 'GRID', ierr)
712 call rpn_comm_bcast(hco%lon, size(hco%lon), 'MPI_REAL8', 0, 'GRID', ierr)
713 call rpn_comm_bcast(hco%lat2d_4, size(hco%lat2d_4), 'MPI_REAL4', 0, 'GRID', ierr)
714 call rpn_comm_bcast(hco%lon2d_4, size(hco%lon2d_4), 'MPI_REAL4', 0, 'GRID', ierr)
715 call rpn_comm_bcast(hco%dlat, 1, 'MPI_REAL8', 0, 'GRID', ierr)
716 call rpn_comm_bcast(hco%dlon, 1, 'MPI_REAL8', 0, 'GRID', ierr)
717 call rpn_comm_bcast(hco%global, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
718 call rpn_comm_bcast(hco%rotated, 1, 'MPI_LOGICAL', 0, 'GRID', ierr)
719 call rpn_comm_bcast(hco%xlat1, 1, 'MPI_REAL8', 0, 'GRID', ierr)
720 call rpn_comm_bcast(hco%xlon1, 1, 'MPI_REAL8', 0, 'GRID', ierr)
721 call rpn_comm_bcast(hco%xlat2, 1, 'MPI_REAL8', 0, 'GRID', ierr)
722 call rpn_comm_bcast(hco%xlon2, 1, 'MPI_REAL8', 0, 'GRID', ierr)
723 call rpn_comm_bcast(hco%xlat1_yan, 1, 'MPI_REAL8', 0, 'GRID', ierr)
724 call rpn_comm_bcast(hco%xlon1_yan, 1, 'MPI_REAL8', 0, 'GRID', ierr)
725 call rpn_comm_bcast(hco%xlat2_yan, 1, 'MPI_REAL8', 0, 'GRID', ierr)
726 call rpn_comm_bcast(hco%xlon2_yan, 1, 'MPI_REAL8', 0, 'GRID', ierr)
727 if (hco%grtyp == 'U') then
728 if (mmpi_myid > 0) then
729 allocate(hco%tictacU(5 + 2 * (10 + hco%ni + hco%nj/2)))
730 end if
731 call rpn_comm_bcast(hco%tictacU, size(hco%tictacU), 'MPI_REAL4', 0, 'GRID', ierr)
732 end if
733
734 if (mmpi_myid > 0) then
735 if (hco%grtyp == 'G' .or. hco%grtyp == 'B') then
736 hco%EZscintID = ezqkdef(hco%ni, hco%nj, hco%grtyp, hco%ig1, hco%ig2, hco%ig3, hco%ig4, 0)
737 else
738 ! special treatment since EZscintID not properly communicated: keep as is
739 write(*,*) 'hco_mpiBcast: Warning! Grid ID for EZSCINT not communicated for grtyp = ', hco%grtyp
740 write(*,*) 'hco_mpiBcast: Warning! Grid ID for EZSCINT equals = ', hco%EZscintID
741 end if
742 end if
743
744 write(*,*) 'hco_mpiBcast: done'
745
746 end subroutine hco_mpiBcast
747
748 !--------------------------------------------------------------------------
749 ! Equal ?
750 !--------------------------------------------------------------------------
751 function hco_equal(hco1, hco2) result(equal)
752 !
753 !:Purpose: to check if two given hco strucures are equal or not
754 !
755 implicit none
756
757 ! Arguments:
758 type(struct_hco), pointer, intent(in) :: hco1
759 type(struct_hco), pointer, intent(in) :: hco2
760 ! Result:
761 logical :: equal
762
763 equal = .true.
764 equal = equal .and. (hco1%ni == hco2%ni)
765 equal = equal .and. (hco1%nj == hco2%nj)
766 if (.not. equal) then
767 write(*,*) 'hco_equal: dimensions not equal ', hco1%ni, hco1%nj, hco2%ni, hco2%nj
768 return
769 end if
770
771 equal = equal .and. (hco1%grtyp == hco2%grtyp)
772 if (.not. equal) then
773 write(*,*) 'hco_equal: grid type not equal'
774 return
775 end if
776
777 equal = equal .and. (hco1%dlat == hco2%dlat)
778 equal = equal .and. (hco1%dlon == hco2%dlon)
779 if (.not. equal) then
780 write(*,*) 'hco_equal: grid spacing not equal'
781 return
782 end if
783
784 if(hco1%grtyp == 'G' .or. hco1%grtyp == 'B') then
785 equal = equal .and. (hco1%ig2 == hco2%ig2)
786 if (.not. equal) then
787 write(*,*) 'hco_equal: Gaussian grid ig2 not equal'
788 return
789 end if
790 end if
791
792 equal = equal .and. (hco1%rotated .eqv. hco2%rotated)
793 equal = equal .and. (hco1%xlat1 == hco2%xlat1)
794 equal = equal .and. (hco1%xlon1 == hco2%xlon1)
795 equal = equal .and. (hco1%xlat2 == hco2%xlat2)
796 equal = equal .and. (hco1%xlon2 == hco2%xlon2)
797 equal = equal .and. (hco1%xlat1_yan == hco2%xlat1_yan)
798 equal = equal .and. (hco1%xlon1_yan == hco2%xlon1_yan)
799 equal = equal .and. (hco1%xlat2_yan == hco2%xlat2_yan)
800 equal = equal .and. (hco1%xlon2_yan == hco2%xlon2_yan)
801 if (.not. equal) then
802 write(*,*) 'hco_equal: rotation not equal: ', hco1%rotated, hco2%rotated
803 write(*,*) 'hco_equal: xlat1: ', hco1%xlat1, hco2%xlat1
804 write(*,*) 'hco_equal: xlat2: ', hco1%xlat2, hco2%xlat2
805 write(*,*) 'hco_equal: xlon1: ', hco1%xlon1, hco2%xlon1
806 write(*,*) 'hco_equal: xlon2: ', hco1%xlon2, hco2%xlon2
807 write(*,*) 'hco_equal: xlat1_yan: ', hco1%xlat1_yan, hco2%xlat1_yan
808 write(*,*) 'hco_equal: xlat2_yan: ', hco1%xlat2_yan, hco2%xlat2_yan
809 write(*,*) 'hco_equal: xlon1_yan: ', hco1%xlon1_yan, hco2%xlon1_yan
810 write(*,*) 'hco_equal: xlon2_yan: ', hco1%xlon2_yan, hco2%xlon2_yan
811 return
812 end if
813
814 equal = equal .and. all(hco1%lat(:) == hco2%lat(:))
815 equal = equal .and. all(hco1%lon(:) == hco2%lon(:))
816 if (.not. equal) then
817 write(*,*) 'hco_equal: lat/lon not equal'
818 return
819 end if
820
821 end function hco_equal
822
823 !--------------------------------------------------------------------------
824 ! hco_deallocate
825 !--------------------------------------------------------------------------
826 subroutine hco_deallocate(hco)
827 implicit none
828
829 ! Arguments:
830 type(struct_hco), pointer, intent(inout) :: hco
831
832 if (allocated(hco % lat)) deallocate(hco % lat)
833 if (allocated(hco % lon)) deallocate(hco % lon)
834 if (allocated(hco % lat2d_4)) deallocate(hco % lat2d_4)
835 if (allocated(hco % lon2d_4)) deallocate(hco % lon2d_4)
836 if (allocated(hco % tictacU)) deallocate(hco % tictacU)
837
838 if (associated(hco)) deallocate(hco)
839 nullify(hco)
840
841 end subroutine hco_deallocate
842
843 !--------------------------------------------------------------------------
844 ! grid_mask
845 !--------------------------------------------------------------------------
846 subroutine grid_mask(F_mask_8,dx,dy,xg,yg,ni,nj)
847 !
848 !:Purpose: 1) Find out where YIN lat lon points are in (YAN) grid with call to smat.
849 ! 2) If they are not outside of Yin grid, put area to zero for those points.
850 !
851 ! Author Qaddouri
852 !
853 implicit none
854
855 ! Arguments:
856 integer, intent(in) :: Ni
857 integer, intent(in) :: Nj
858 real(8) , intent(out) :: F_mask_8(Ni,Nj)
859 real(8), intent(in) :: dx
860 real(8), intent(in) :: dy
861 real(4), intent(in) :: xg(ni)
862 real(4), intent(in) :: yg(nj)
863
864 ! Locals:
865 integer :: lonIndex,latIndex,np_subd
866 real(8) :: poids(ni,nj),x_a_4,y_a_4,sp,sf,sp1,sf1
867 real(4) :: area_4(ni,nj)
868
869 np_subd = 4*ni
870
871 sp = 0.d0
872 sf = 0.d0
873
874 do latIndex = 1, nj
875 y_a_4 = yg(latIndex)
876 do lonIndex = 1, ni
877
878 x_a_4 = xg(lonIndex)-acos(-1.d0)
879
880 area_4(lonIndex,latIndex) = dx*dy*cos(yg(latIndex))
881 poids (lonIndex,latIndex) = yyg_weight (x_a_4,y_a_4,dx,dy,np_subd)
882
883 !Check if poids <0
884 if (poids(lonIndex,latIndex)*(1.d0-poids(lonIndex,latIndex)) > 0.d0) then
885 sp = sp + poids(lonIndex,latIndex)*area_4(lonIndex,latIndex)
886 else if (abs(poids(lonIndex,latIndex)-1.d0) < 1.d-14) then
887 sf = sf + poids(lonIndex,latIndex)*area_4(lonIndex,latIndex)
888 end if
889
890 end do
891 end do
892
893 !Correct and scale poids
894 !-----------------------
895 sp1 = 0.d0
896 sf1 = 0.d0
897
898 do latIndex = 1, nj
899 do lonIndex = 1, ni
900
901 x_a_4 = poids(lonIndex,latIndex)*(2.d0*acos(-1.d0) - sf)/sp
902
903 if (poids(lonIndex,latIndex)*(1.d0-poids(lonIndex,latIndex)) > 0.d0) then
904 poids(lonIndex,latIndex) = min(1.0d0, x_a_4)
905 end if
906 if (poids(lonIndex,latIndex)*(1.0-poids(lonIndex,latIndex)) > 0.d0) then
907 sp1 = sp1 + poids(lonIndex,latIndex)*area_4(lonIndex,latIndex)
908 else if (abs(poids(lonIndex,latIndex)-1.d0) < 1.d-14) then
909 sf1 = sf1 + poids(lonIndex,latIndex)*area_4(lonIndex,latIndex)
910 end if
911
912 end do
913 end do
914
915 !Correct
916 !-------
917 do latIndex = 1, nj
918 do lonIndex = 1, ni
919 x_a_4 = poids(lonIndex,latIndex)*(2.d0*acos(-1.d0) - sf1)/sp1
920
921 if (poids(lonIndex,latIndex)*(1.d0-poids(lonIndex,latIndex)) > 0.d0) then
922 poids(lonIndex,latIndex) = min(1.d0, x_a_4)
923 end if
924
925 end do
926 end do
927
928 F_mask_8 = 0.d0
929 do latIndex=1,nj
930 do lonIndex = 1,ni
931 F_mask_8(lonIndex,latIndex) = poids(lonIndex,latIndex)
932 end do
933 end do
934
935 end subroutine grid_mask
936
937 !--------------------------------------------------------------------------
938 ! inter_curve_boundary_yy
939 !--------------------------------------------------------------------------
940 subroutine inter_curve_boundary_yy (x,y,xi,yi,np)
941 !
942 !:Purpose: compute the intersections between a line and the panel
943 ! (yin or yang) boundary. The line passes through the panel
944 ! center point (0, 0) and the cell center point (x, y).
945 !
946 ! Author A. Qaddouri. October 2016
947 !
948 ! Note: this routine has been taken and adjusted from a routine
949 ! with the same name in the GEM model.
950 !
951 !:Arguments: input: (x, y): longitude, latitude of the cell
952 ! center point,
953 ! np: workspace,
954 ! output: (xi, yi): longitude, latitude of the
955 ! intersection point.
956 implicit none
957
958 ! Arguments:
959 real(8), intent(in) :: x
960 real(8), intent(in) :: y
961 real(8), intent(out) :: xi
962 real(8), intent(out) :: yi
963 integer, intent(in) :: np
964
965 ! Locals:
966 real(8) :: tol, pi, xmin, ymin, xb
967 real(8) :: xc, yc, s1, s2, x1, test, dxs
968 real(8) :: xp1, xp2, xr1, yr1, xr2, yr2
969 integer :: i
970
971 tol = 1.0d-16
972 pi = MPC_PI_R8
973 xmin = -3.d0*pi/4.d0
974 ymin = -pi/4.d0
975 xb = -0.5d0*pi
976
977 xc = x
978 yc = y
979
980 if (x > 0.d0) xc = - x
981 if (y > 0.d0) yc = - y
982
983 if (abs(xc) < tol) then
984 xi = xc
985 yi = ymin
986 else
987
988 s1 = yc / xc
989 s2 = ymin/(xb-xmin)
990
991 x1 = s2*xmin/(s2-s1)
992 if (x1 > xb) then
993 xi = ymin/s1
994 yi = ymin
995 else
996 test = -1.d0
997 dxs = -xb/(np-1)
998 i = 1
999 do while (test < 0.d0)
1000 xp1 = (i-1)*dxs + xb
1001 xp2 = (i)*dxs + xb
1002 xr1 = atan2(sin(ymin),-cos(ymin)*cos(xp1))
1003 yr1 = asin(cos(ymin)*sin(xp1))
1004 xr2 = atan2(sin(ymin),-cos(ymin)*cos(xp2))
1005 yr2 = asin(cos(ymin)*sin(xp2))
1006 s2 = (yr1-yr2)/(xr1-xr2)
1007 xi = (s2*xr2-yr2)/(s2-s1)
1008 yi = s1*xi
1009 test=(xi-xr1)*(xr2-xi)
1010 i = i+1
1011 end do
1012 end if
1013 end if
1014
1015 if (x > 0.d0) xi = - xi
1016 if (y > 0.d0) yi = - yi
1017
1018 end subroutine inter_curve_boundary_yy
1019
1020 !--------------------------------------------------------------------------
1021 ! hco_weight
1022 !--------------------------------------------------------------------------
1023 subroutine hco_weight(hco, weight)
1024 !
1025 !:Purpose: given the horizontal grid definition of the grid,
1026 ! return appropriate weights for individual points (avoiding
1027 ! double counting in the overlap regions in the case of a Yin-Yang grid).
1028 !
1029 !:Author: Abdessamad Qaddouri and Peter Houtekamer
1030 ! October 2016
1031 !
1032 !:Revision: imported code for the Yin-Yang grid on May 2021 from the EnKF library and
1033 ! combined with code for other grid types from the MIDAS library.
1034 !
1035 implicit none
1036
1037 ! Arguments:
1038 type(struct_hco), intent(in) :: hco ! structure with the specification of the horizontal grid
1039 real(8), intent(out) :: weight(:,:) ! weight to be given when computing a horizontal average
1040
1041 ! Locals:
1042 integer :: sindx
1043 integer :: ni,nj
1044 integer :: lonIndex,latIndex,lonIndexP1,latIndexP1
1045 real(8), allocatable :: F_mask_8(:,:), F_mask(:,:)
1046 real(8) :: deg2rad,dx,dy,sum_weight
1047 real(8) :: lon1,lon2,lon3,lat1,lat2,lat3
1048 real(4), allocatable :: xg(:),yg(:)
1049
1050 deg2rad= MPC_RADIANS_PER_DEGREE_R8
1051 sindx = 6
1052
1053 if (trim(hco%grtyp) == 'U') then ! case of a Yin-Yang grid
1054 write(*,*) 'compute weights for Yin_Yang grid'
1055 ni = nint(hco%tictacU(sindx))
1056 nj = nint(hco%tictacU(sindx+1))
1057 allocate (F_mask_8 (ni,nj))
1058 allocate (F_mask(ni,2*nj))
1059 allocate (xg(ni))
1060 allocate (yg(nj))
1061
1062 dx = hco%tictacU(sindx+10+1) -hco%tictacU(sindx+10)
1063 dy= hco%tictacU(sindx+10+ni+1)-hco%tictacU(sindx+10+ni)
1064 dx= deg2rad* dx
1065 dy= deg2rad* dy
1066 do lonIndex=1,ni
1067 xg(lonIndex)=deg2rad* hco%tictacU(sindx+10+lonIndex-1)
1068 end do
1069 do latIndex=1,nj
1070 yg(latIndex)= deg2rad*hco%tictacU(sindx+10+ni+latIndex-1)
1071 weight (:,latIndex) = cos(deg2rad* hco%tictacU(sindx+10+ni+latIndex-1))
1072 weight (:,nj+latIndex)= weight (:,latIndex)
1073 end do
1074 call grid_mask (F_mask_8,dx,dy,xg,yg,ni,nj)
1075 do latIndex=1,nj
1076 F_mask (:,latIndex) = F_mask_8(:,latIndex)
1077 F_mask (:,nj+latIndex)= F_mask (:,latIndex)
1078 end do
1079 do latIndex=1,nj*2
1080 weight(:,latIndex) = weight(:, latIndex) * F_mask(:, latIndex)
1081 end do
1082 sum_weight=sum(weight)
1083 weight = weight/sum_weight
1084 deallocate(F_mask_8)
1085 deallocate(F_mask)
1086 deallocate(xg)
1087 deallocate(yg)
1088 else
1089 write(*,*) 'compute weights for grid type: ',hco%grtyp
1090 do latIndex=1,hco%nj
1091 latIndexP1 = min(hco%nj,latIndex+1)
1092 do lonIndex=1,hco%ni
1093 lonIndexP1 = min(hco%ni,lonIndex+1)
1094 lon1 = hco%lon2d_4(lonIndex,latIndex)
1095 lon2 = hco%lon2d_4(lonIndexP1,latIndex)
1096 lon3 = hco%lon2d_4(lonIndex,latIndexP1)
1097 lat1 = hco%lat2d_4(lonIndex,latIndex)
1098 lat2 = hco%lat2d_4(lonIndexP1,latIndex)
1099 lat3 = hco%lat2d_4(lonIndex,latIndexP1)
1100 dx = phf_calcDistance(lat1, lon1, lat2, lon2)/1000.0D0
1101 dy = phf_calcDistance(lat1, lon1, lat3, lon3)/1000.0D0
1102 weight(lonIndex,latIndex) = dx * dy
1103 end do
1104 end do
1105 sum_weight=sum(weight)
1106 weight = weight/sum_weight
1107 end if
1108
1109 end subroutine hco_weight
1110
1111 !--------------------------------------------------------------------------
1112 ! yyg_weight
1113 !--------------------------------------------------------------------------
1114 real(8) function yyg_weight (x,y,dx,dy,np)
1115 !
1116 !:Purpose: Based on a Draft from Zerroukat (2013) - Evaluates weight
1117 ! for each cell, so that the overlap is computed once.
1118 !
1119 !:Author: Author Abdessamad Qaddouri -- Summer 2014
1120 !
1121 !:Note: this routine has been taken and adjusted from a routine
1122 ! with the same name in the GEM model.
1123 !
1124 implicit none
1125
1126 ! Arguments:
1127 real(8), intent(in) :: x ! x,y: (lon, lat) in radians of the cell center point.
1128 real(8), intent(in) :: y
1129 real(8), intent(in) :: dx ! horizontal grid resolution in radians
1130 real(8), intent(in) :: dy
1131 integer, intent(in) :: np ! working dimension
1132
1133 ! Locals:
1134 real(8) :: pi, xmin, xmax, ymin, ymax, xb1, xb2
1135 real(8) :: t1x, t2x, t1y, dcell, xi, yi, di, dp, df, d
1136
1137 pi = MPC_PI_R8
1138 xmin = -3.d0*pi/4.d0 ; xmax = 3.d0*pi/4.d0
1139 ymin = -pi/4.d0 ; ymax = pi/4.d0
1140 xb1 = -0.5d0*pi ; xb2 = 0.5d0*pi
1141
1142 t1x = (x-xmin)*(xmax-x)
1143 t2x = (x-xb1)*(xb2-x)
1144 t1y = (y-ymin)*(ymax-y)
1145
1146 if (t1x < 0.d0 .or. t1y < 0.d0) then
1147 yyg_weight = 0.0
1148 else if (t2x > 0.d0 .and. t1y > 0.d0) then
1149 yyg_weight = 1.d0
1150 else
1151 dcell = 0.5d0*dsqrt(dx**2 + dy**2)
1152
1153 call inter_curve_boundary_yy (x, y, xi, yi, np)
1154
1155 di = sqrt(xi**2 + yi**2)
1156 dp = sqrt(x**2 + y**2)
1157 df = dp - di
1158 d = min(max(-dcell,df),dcell)
1159 yyg_weight = 0.5d0*(1.d0 - (d/dcell))
1160 end if
1161
1162 end function yyg_weight
1163
1164 !--------------------------------------------------------------------------
1165 ! hco_setupYgrid
1166 !--------------------------------------------------------------------------
1167 subroutine hco_setupYgrid(hco, ni, nj)
1168 !
1169 !:Purpose: to initialize hco structure for a Y grid
1170 !
1171 implicit none
1172
1173 ! Arguments:
1174 type(struct_hco), pointer, intent(inout) :: hco
1175 integer, intent(in) :: ni
1176 integer, intent(in) :: nj
1177
1178 allocate(hco)
1179 if (mmpi_myid == 0) then
1180 hco%initialized = .true.
1181 hco%ni = ni
1182 hco%nj = nj
1183 hco%grtyp = 'Y'
1184 hco%grtypTicTac = 'L'
1185 if (allocated(hco%lat2d_4)) then
1186 deallocate(hco%lat2d_4)
1187 deallocate(hco%lon2d_4)
1188 end if
1189 allocate(hco%lat2d_4(ni, nj))
1190 allocate(hco%lon2d_4(ni, nj))
1191 hco%xlat1 = 0.d0
1192 hco%xlon1 = 0.d0
1193 hco%xlat2 = 1.d0
1194 hco%xlon2 = 1.d0
1195 end if
1196
1197 end subroutine hco_setupYgrid
1198
1199end module horizontalCoord_mod