dyn_mpas_init_phase3 Subroutine

private subroutine dyn_mpas_init_phase3(self, number_of_constituents, pio_file)

Uses

    • mpas_bootstrapping
    • mpas_derived_types
    • pio
    • mpas_pool_routines
  • proc~~dyn_mpas_init_phase3~~UsesGraph proc~dyn_mpas_init_phase3 mpas_dynamical_core_type%dyn_mpas_init_phase3 mpas_bootstrapping mpas_bootstrapping proc~dyn_mpas_init_phase3->mpas_bootstrapping mpas_derived_types mpas_derived_types proc~dyn_mpas_init_phase3->mpas_derived_types mpas_pool_routines mpas_pool_routines proc~dyn_mpas_init_phase3->mpas_pool_routines pio pio proc~dyn_mpas_init_phase3->pio

This subroutine follows the stand-alone MPAS subdriver after the check on the existence of the "streams." file up to, but not including, the point where atm_core_init is called. It completes MPAS framework initialization, including the allocation of all blocks and fields managed by MPAS. However, note that scalars are allocated, but not yet defined. dyn_mpas_define_scalar must be called afterwards. Also note that MPAS uses the term "scalar", but CAM-SIMA calls it "constituent". Ported and refactored for CAM-SIMA. (KCW, 2024-03-06)

Type Bound

mpas_dynamical_core_type

Arguments

Type IntentOptional Attributes Name
class(mpas_dynamical_core_type), intent(inout) :: self
integer, intent(in) :: number_of_constituents
type(file_desc_t), intent(in), pointer :: pio_file

Calls

proc~~dyn_mpas_init_phase3~~CallsGraph proc~dyn_mpas_init_phase3 mpas_dynamical_core_type%dyn_mpas_init_phase3 mpas_bootstrap_framework_phase1 mpas_bootstrap_framework_phase1 proc~dyn_mpas_init_phase3->mpas_bootstrap_framework_phase1 mpas_bootstrap_framework_phase2 mpas_bootstrap_framework_phase2 proc~dyn_mpas_init_phase3->mpas_bootstrap_framework_phase2 mpas_pool_add_config mpas_pool_add_config proc~dyn_mpas_init_phase3->mpas_pool_add_config mpas_pool_add_dimension mpas_pool_add_dimension proc~dyn_mpas_init_phase3->mpas_pool_add_dimension mpas_pool_get_dimension mpas_pool_get_dimension proc~dyn_mpas_init_phase3->mpas_pool_get_dimension pio_file_is_open pio_file_is_open proc~dyn_mpas_init_phase3->pio_file_is_open proc~dyn_mpas_debug_print mpas_dynamical_core_type%dyn_mpas_debug_print proc~dyn_mpas_init_phase3->proc~dyn_mpas_debug_print proc~dyn_mpas_get_pool_pointer mpas_dynamical_core_type%dyn_mpas_get_pool_pointer proc~dyn_mpas_init_phase3->proc~dyn_mpas_get_pool_pointer proc~stringify stringify proc~dyn_mpas_init_phase3->proc~stringify proc~dyn_mpas_debug_print->proc~stringify mpas_pool_get_subpool mpas_pool_get_subpool proc~dyn_mpas_get_pool_pointer->mpas_pool_get_subpool

Called by

proc~~dyn_mpas_init_phase3~~CalledByGraph proc~dyn_mpas_init_phase3 mpas_dynamical_core_type%dyn_mpas_init_phase3 proc~model_grid_init model_grid_init proc~model_grid_init->proc~dyn_mpas_init_phase3

Variables

Type Visibility Attributes Name Initial
character(len=strkind), private :: mesh_filename
integer, private :: mesh_format
type(mpas_pool_type), private, pointer :: mpas_pool
integer, private, pointer :: num_scalars
character(len=*), private, parameter :: subname = 'dyn_mpas_subdriver::dyn_mpas_init_phase3'

Source Code

    subroutine dyn_mpas_init_phase3(self, number_of_constituents, pio_file)
        ! Module(s) from external libraries.
        use pio, only: file_desc_t, pio_file_is_open
        ! Module(s) from MPAS.
        use mpas_bootstrapping, only: mpas_bootstrap_framework_phase1, mpas_bootstrap_framework_phase2
        use mpas_derived_types, only: mpas_io_pnetcdf, mpas_pool_type
        use mpas_pool_routines, only: mpas_pool_add_config, mpas_pool_add_dimension, mpas_pool_get_dimension

        class(mpas_dynamical_core_type), intent(inout) :: self
        integer, intent(in) :: number_of_constituents
        type(file_desc_t), pointer, intent(in) :: pio_file

        character(*), parameter :: subname = 'dyn_mpas_subdriver::dyn_mpas_init_phase3'
        character(strkind) :: mesh_filename
        integer :: mesh_format
        integer, pointer :: num_scalars
        type(mpas_pool_type), pointer :: mpas_pool

        call self % debug_print(log_level_debug, subname // ' entered')

        nullify(mpas_pool)
        nullify(num_scalars)

        ! In MPAS, there must be at least one constituent, `qv`, which denotes water vapor mixing ratio.
        ! Because MPAS has some hard-coded array accesses through the `index_qv` index, it will crash
        ! (i.e., segmentation fault due to invalid memory access) if `qv` is not allocated.
        self % number_of_constituents = max(1, number_of_constituents)

        call self % debug_print(log_level_info, 'Number of constituents is ' // stringify([self % number_of_constituents]))

        ! Adding a config named "cam_pcnst" with the number of constituents will indicate to MPAS that
        ! it is operating as a dynamical core, and therefore it needs to allocate scalars separately
        ! from other Registry-defined fields. The special logic is located in `atm_setup_block`.
        ! This must be done before calling `mpas_bootstrap_framework_phase1`.
        call mpas_pool_add_config(self % domain_ptr % configs, 'cam_pcnst', self % number_of_constituents)

        ! Not actually used because a PIO file descriptor is directly supplied.
        mesh_filename = 'external mesh'
        mesh_format = mpas_io_pnetcdf

        call self % debug_print(log_level_info, 'Checking PIO file descriptor')

        if (.not. associated(pio_file)) then
            call self % model_error('Invalid PIO file descriptor', subname, __LINE__)
        end if

        if (.not. pio_file_is_open(pio_file)) then
            call self % model_error('Invalid PIO file descriptor', subname, __LINE__)
        end if

        call self % debug_print(log_level_info, 'Bootstrapping MPAS framework (Phase 1/2)')

        ! Finish setting up blocks.
        call mpas_bootstrap_framework_phase1(self % domain_ptr, mesh_filename, mesh_format, pio_file_desc=pio_file)

        call self % debug_print(log_level_info, 'Bootstrapping MPAS framework (Phase 2/2)')

        ! Finish setting up fields.
        call mpas_bootstrap_framework_phase2(self % domain_ptr, pio_file_desc=pio_file)

        ! "num_scalars" is a dimension variable, but it only exists in MPAS "state" pool.
        ! Fix this inconsistency by also adding it to MPAS "dimension" pool.
        call self % get_pool_pointer(mpas_pool, 'state')

        call mpas_pool_get_dimension(mpas_pool, 'num_scalars', num_scalars)

        if (.not. associated(num_scalars)) then
            call self % model_error('Failed to find variable "num_scalars"', subname, __LINE__)
        end if

        ! While we are at it, check if its value is consistent.
        if (num_scalars /= self % number_of_constituents) then
            call self % model_error('Failed to allocate constituents', subname, __LINE__)
        end if

        call mpas_pool_add_dimension(self % domain_ptr % blocklist % dimensions, 'num_scalars', num_scalars)

        nullify(mpas_pool)
        nullify(num_scalars)

        ! At this point, what follows next depends on the specific use case. In no particular order:
        ! * Use `dyn_mpas_define_scalar` to define the names of constituents at run-time.
        ! * Use `dyn_mpas_read_write_stream` to read mesh variables.
        !   * Follow up with a call to `dyn_mpas_compute_unit_vector` immediately. This is by design.
        ! * For setting analytic initial condition, use `get_variable_pointer` to inject data directly into MPAS memory.
        !   * Use `dyn_mpas_compute_edge_wind` where appropriate.
        !   * Use `dyn_mpas_exchange_halo` where appropriate.
        ! * Use `dyn_mpas_read_write_stream` to read initial condition or restart.
        ! * Finally, use `dyn_mpas_init_phase4` to conclude the initialization of MPAS dynamical core.
        call self % debug_print(log_level_debug, subname // ' completed')
    end subroutine dyn_mpas_init_phase3