@@ -26,6 +26,10 @@ module physics_data
26
26
module procedure check_field_3d
27
27
end interface check_field
28
28
29
+ interface read_constituent_dimensioned_field
30
+ module procedure read_constituent_dimensioned_field_2d
31
+ end interface read_constituent_dimensioned_field
32
+
29
33
! ==============================================================================
30
34
CONTAINS
31
35
! ==============================================================================
@@ -325,6 +329,197 @@ subroutine read_field_3d(file, std_name, var_names, vcoord_name, &
325
329
end if
326
330
end subroutine read_field_3d
327
331
332
+ subroutine read_constituent_dimensioned_field_2d (const_props , file , std_name , base_var_names , timestep , field_array , initial_value )
333
+ use shr_assert_mod, only: shr_assert_in_domain
334
+ use shr_sys_mod, only: shr_sys_flush
335
+ use pio, only: file_desc_t, var_desc_t
336
+ use spmd_utils, only: masterproc
337
+ use cam_pio_utils, only: cam_pio_find_var
338
+ use cam_abortutils, only: endrun
339
+ use cam_logfile, only: iulog
340
+ use cam_field_read, only: cam_read_field
341
+ use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t
342
+ use phys_vars_init_check, only: mark_as_read_from_file
343
+ use phys_vars_init_check, only: phys_var_stdnames, input_var_names, phys_var_num
344
+
345
+ ! Dummy arguments
346
+ type (ccpp_constituent_prop_ptr_t), intent (in ) :: const_props(:) ! Constituent properties
347
+ type (file_desc_t), intent (inout ) :: file
348
+ character (len=* ), intent (in ) :: std_name ! Standard name of base variable.
349
+ character (len=* ), intent (in ) :: base_var_names(:) ! "Base" name(s) used to construct variable name (base_constname)
350
+ integer , intent (in ) :: timestep ! Timestep to read [count]
351
+ real (kind_phys), intent (inout ) :: field_array(:,:) ! Output field array (ncol, pcnst)
352
+ real (kind_phys), optional , intent (in ) :: initial_value ! Default value if not found
353
+
354
+ ! Local variables
355
+ logical :: var_found
356
+ character (len= 128 ) :: constituent_name
357
+ character (len= 256 ) :: file_var_name
358
+ character (len= 256 ) :: found_name
359
+ character (len= 512 ) :: missing_vars
360
+ type (var_desc_t) :: vardesc
361
+ real (kind_phys), allocatable :: buffer(:)
362
+ integer :: const_idx, base_idx
363
+ integer :: ierr
364
+ real (kind_phys) :: default_value
365
+ logical :: has_initial_value
366
+ logical :: any_missing
367
+
368
+ ! For construction of constituent short name mapping
369
+ character (len= 128 ), allocatable :: constituent_short_names(:)
370
+ character (len= 128 ) :: constituent_std_name
371
+ integer :: n
372
+ integer :: const_input_idx
373
+
374
+ character (len=* ), parameter :: subname = ' read_constituent_dimensioned_field: '
375
+
376
+ ! Check if initial value was provided
377
+ has_initial_value = present (initial_value)
378
+
379
+ ! Initialize tracking variables
380
+ any_missing = .false.
381
+ missing_vars = ' '
382
+
383
+ ! Allocate temporary buffer
384
+ allocate (buffer(size (field_array, 1 )), stat= ierr)
385
+ if (ierr /= 0 ) then
386
+ call endrun(subname// ' Failed to allocate buffer' )
387
+ end if
388
+
389
+ ! REMOVECAM:
390
+ ! Because the constituent properties pointer contains standard names, and not input constituent names
391
+ ! (e.g., Q, CLDLIQ, ...) which are used in the input file names,
392
+ ! we have to construct a mapping of the standard names to the short input IC file names
393
+ ! When CAM is retired and only standard names are used for constituents, this mapping can be removed.
394
+ allocate (constituent_short_names(size (const_props)), stat= ierr)
395
+ if (ierr /= 0 ) then
396
+ call endrun(subname// ' Failed to allocate constituent_short_names' )
397
+ end if
398
+
399
+ const_shortmap_loop: do const_idx = 1 , size (const_props)
400
+ ! Get constituent standard name.
401
+ call const_props(const_idx)% standard_name(constituent_std_name)
402
+
403
+ ! Check if constituent standard name is in the registry to look up its IC name
404
+ ! n.b. this assumes that the first IC name is the short name
405
+ const_input_idx = - 1
406
+ phys_inputvar_loop: do n = 1 , phys_var_num
407
+ if (trim (phys_var_stdnames(n)) == trim (constituent_std_name)) then
408
+ const_input_idx = n
409
+ exit phys_inputvar_loop
410
+ end if
411
+ end do
412
+
413
+ if (const_input_idx > 0 ) then
414
+ ! Use the first entry from the input_var_names -- assumed to be short name.
415
+ constituent_short_names(const_idx) = trim (input_var_names(1 , const_input_idx))
416
+ else
417
+ ! Use the standard name itself if not found in registry.
418
+ constituent_short_names(const_idx) = trim (constituent_std_name)
419
+ end if
420
+ end do const_shortmap_loop
421
+ ! END REMOVECAM
422
+
423
+ ! Initialize field array to default value (only if initial_value provided)
424
+ if (has_initial_value) then
425
+ field_array(:,:) = initial_value
426
+ end if
427
+
428
+ ! Loop through all possible base names to find correct base name.
429
+ ! Note this assumes that the same base name is used for all constituents.
430
+ ! i.e., there cannot be something like cam_in_cflx_Q & cflx_CLDLIQ in one file.
431
+ base_idx_loop: do base_idx = 1 , size (base_var_names)
432
+ ! Loop through all constituents
433
+ const_idx_loop: do const_idx = 1 , size (const_props)
434
+ ! Get constituent short name
435
+ constituent_name = constituent_short_names(const_idx)
436
+
437
+ ! Create file variable name: <base_var_name>_<constituent_name>
438
+ file_var_name = trim (base_var_names(base_idx)) // ' _' // trim (constituent_name)
439
+
440
+ ! Try to find variable in file
441
+ var_found = .false.
442
+ call cam_pio_find_var(file, [file_var_name], found_name, vardesc, var_found)
443
+
444
+ if (var_found) then
445
+ exit base_idx_loop
446
+ endif
447
+ end do const_idx_loop
448
+ end do base_idx_loop
449
+
450
+ ! Once base_idx is identified, use it in the actual constituent loop:
451
+ const_read_loop: do const_idx = 1 , size (const_props)
452
+ ! Get constituent short name
453
+ constituent_name = constituent_short_names(const_idx)
454
+
455
+ ! Create file variable name: <base_var_name>_<constituent_name>
456
+ file_var_name = trim (base_var_names(base_idx)) // ' _' // trim (constituent_name)
457
+
458
+ ! Try to find variable in file
459
+ var_found = .false.
460
+ call cam_pio_find_var(file, [file_var_name], found_name, vardesc, var_found)
461
+
462
+ if (var_found) then
463
+ ! Read the variable
464
+ if (masterproc) then
465
+ write (iulog, * ) ' Reading constituent-dimensioned input field, ' , trim (found_name)
466
+ call shr_sys_flush(iulog)
467
+ end if
468
+
469
+ call cam_read_field(found_name, file, buffer, var_found, timelevel= timestep)
470
+
471
+ if (var_found) then
472
+ ! Copy to correct constituent index in field array
473
+ field_array(:, const_idx) = buffer(:)
474
+
475
+ ! Check for NaN values
476
+ call shr_assert_in_domain(field_array(:, const_idx), is_nan= .false. , &
477
+ varname= trim (found_name), &
478
+ msg= subname// ' NaN found in ' // trim (found_name))
479
+ else
480
+ ! Failed to read even though variable was found
481
+ any_missing = .true.
482
+ if (len_trim (missing_vars) > 0 ) then
483
+ missing_vars = trim (missing_vars) // ' , ' // trim (file_var_name)
484
+ else
485
+ missing_vars = trim (file_var_name)
486
+ end if
487
+ end if
488
+ else
489
+ ! Variable not found in file
490
+ any_missing = .true.
491
+ if (len_trim (missing_vars) > 0 ) then
492
+ missing_vars = trim (missing_vars) // ' , ' // trim (file_var_name)
493
+ else
494
+ missing_vars = trim (file_var_name)
495
+ end if
496
+
497
+ if (has_initial_value) then
498
+ ! Use default value (already set above)
499
+
500
+ if (masterproc) then
501
+ write (iulog, * ) ' Constituent-dimensioned field ' , trim (file_var_name), &
502
+ ' not found, using default value for constituent ' , trim (constituent_name)
503
+ call shr_sys_flush(iulog)
504
+ end if
505
+ end if
506
+ end if
507
+ end do const_read_loop
508
+
509
+ ! Check if we should fail due to missing variables
510
+ if (any_missing .and. .not. has_initial_value) then
511
+ call endrun(subname// ' Required constituent-dimensioned variables not found: ' // trim (missing_vars))
512
+ end if
513
+
514
+ ! Mark the base variable as read from file (only if no errors)
515
+ call mark_as_read_from_file(std_name)
516
+
517
+ ! Clean up
518
+ deallocate (constituent_short_names)
519
+ deallocate (buffer)
520
+
521
+ end subroutine read_constituent_dimensioned_field_2d
522
+
328
523
subroutine check_field_2d (file , var_names , timestep , current_value , &
329
524
stdname , min_difference , min_relative_value , is_first , diff_found )
330
525
use pio, only: file_desc_t, var_desc_t
0 commit comments