File ColumnInterface_Mod.F90¶
File List > core > ColumnInterface_Mod.F90
Go to the documentation of this file
!========================================================================
!! Virtual Column Interface Module
!!
!! Provides a column-based interface to multi-dimensional atmospheric data.
!! This allows column-based processes to work transparently with both 1D
!! (column) and multi-dimensional (2D/3D) host models.
!!
!! Key features:
!! - Zero-copy access via pointers
!! - OpenMP/OpenACC friendly
!! - Support for 1D, 2D, and 3D grids
!!
!! @author CATChem Development Team
!! @date 2025
!! @version 1.0
!!
!! This module provides a column-based interface to multi-dimensional atmospheric data,
!! allowing column-based processes to work transparently with both 1D (column) and
!! multi-dimensional (2D/3D) host models.
!!
!! @details
!! - Zero-copy access via pointers
!! - OpenMP/OpenACC friendly
!! - Support for 1D, 2D, and 3D grids
!!
module columninterface_mod
use precision_mod, only: fp
use error_mod, only: cc_success, cc_failure
use chemstate_mod, only: chemstatetype
use metstate_mod, only: metstatetype
use gridgeometry_mod, only: gridgeometrytype
use virtualcolumn_mod, only: virtualcolumntype
! use EmisState_Mod, only: EmisStateType
implicit none
private
! Forward declaration for GridManagerType to avoid circular dependency
type :: gridmanagertype
end type gridmanagertype
public :: columnviewtype
public :: create_column_view
! public :: VirtualColumnType
public :: columnprocessortype
!========================================================================
!! Column View Type
!!
!! Provides column-based access to multi-dimensional state data.
!! Supports both direct column models and virtual columns from 3D data.
!========================================================================
type :: columnviewtype
private
! Grid information
integer :: grid_type
integer :: nx
integer :: ny
integer :: nlev
integer :: current_i
integer :: current_j
! State object references (optional - can be null for simple column access)
type(MetStateType), pointer :: met_state => null()
type(ChemStateType), pointer :: chem_state => null()
! Column data pointers (for current column)
real(fp), pointer :: met_column(:) => null()
real(fp), pointer :: chem_column(:,:) => null()
real(fp), pointer :: emis_column(:,:) => null()
contains
procedure :: init => column_view_init
procedure :: set_column_position => column_view_set_position
procedure :: get_met_column_ptr => column_view_get_met_ptr
procedure :: get_chem_column_ptr => column_view_get_chem_ptr
procedure :: get_emis_column_ptr => column_view_get_emis_ptr
procedure :: apply_column_tendency => column_view_apply_tendency
procedure :: cleanup => column_view_cleanup
end type columnviewtype
type :: columnprocessortype
private
type(VirtualColumnType), allocatable :: columns(:)
integer :: n_columns = 0
integer :: current_column = 1
contains
procedure :: init => processor_init
procedure :: add_column => processor_add_column
procedure :: process_all => processor_process_all
procedure :: get_column => processor_get_column
procedure :: get_current_column => processor_get_current_column
procedure :: next_column => processor_next_column
procedure :: reset => processor_reset
procedure :: cleanup => processor_cleanup
end type columnprocessortype
abstract interface
subroutine column_process_interface(column, rc)
import :: virtualcolumntype
type(VirtualColumnType), intent(inout) :: column
integer, intent(out) :: rc
end subroutine column_process_interface
end interface
contains
!========================================================================
!! Initialize column view with state objects
!========================================================================
subroutine column_view_init(this, met_state, chem_state, rc)
class(ColumnViewType), intent(inout) :: this
type(MetStateType), intent(in), target, optional :: met_state
type(ChemStateType), intent(in), target, optional :: chem_state
integer, intent(out) :: rc
rc = cc_success
! Store state references if provided
if (present(met_state)) this%met_state => met_state
if (present(chem_state)) this%chem_state => chem_state
! Get grid dimensions from MetState if available
if (associated(this%met_state)) then
! For now, use placeholder dimensions
this%nx = 1
this%ny = 1
this%nlev = 50
else
! Use default dimensions
this%nx = 1
this%ny = 1
this%nlev = 50
endif
if (this%nx == 1 .and. this%ny == 1) then
this%grid_type = 1 ! Pure column model
else if (this%ny == 1) then
this%grid_type = 2 ! 2D (x-z) model
else
this%grid_type = 3 ! 3D (x-y-z) model
endif
! Initialize position
this%current_i = 1
this%current_j = 1
end subroutine column_view_init
!========================================================================
!! Set current column position (for multi-dimensional grids)
!========================================================================
subroutine column_view_set_position(this, i, j, rc)
class(ColumnViewType), intent(inout) :: this
integer, intent(in) :: i, j
integer, intent(out) :: rc
rc = cc_success
! Validate position
if (i < 1 .or. i > this%nx .or. j < 1 .or. j > this%ny) then
print *, 'ERROR: Invalid column position:', i, j
rc = cc_failure
return
endif
this%current_i = i
this%current_j = j
! Update pointers to current column - TODO: implement if needed
rc = cc_success
end subroutine column_view_set_position
!========================================================================
!! Get meteorological column pointer
!========================================================================
function column_view_get_met_ptr(this, field_name) result(column_ptr)
class(ColumnViewType), intent(in) :: this
character(len=*), intent(in) :: field_name
real(fp), pointer :: column_ptr(:)
column_ptr => null()
if (.not. associated(this%met_state)) return
! Real implementation would get field from MetState
! For now, return null pointer
column_ptr => null()
end function column_view_get_met_ptr
!========================================================================
!! Get chemistry column pointer for a species
!========================================================================
function column_view_get_chem_ptr(this, species_name) result(column_ptr)
class(ColumnViewType), intent(in) :: this
character(len=*), intent(in) :: species_name
real(fp), pointer :: column_ptr(:)
column_ptr => null()
if (.not. associated(this%chem_state)) return
! Real implementation would get species from ChemState
! For now, return null pointer
column_ptr => null()
end function column_view_get_chem_ptr
!========================================================================
!! Get emissions column pointer for a species
!========================================================================
function column_view_get_emis_ptr(this, species_name) result(column_ptr)
class(ColumnViewType), intent(in) :: this
character(len=*), intent(in) :: species_name
real(fp), pointer :: column_ptr(:)
! For now, return null pointer since EmisState is commented out
column_ptr => null()
end function column_view_get_emis_ptr
!========================================================================
!! Apply tendency to current column and accumulate in emissions
!========================================================================
subroutine column_view_apply_tendency(this, species_name, tendency_column, &
dt, layer_height, rc)
class(ColumnViewType), intent(inout) :: this
character(len=*), intent(in) :: species_name
real(fp), intent(in) :: tendency_column(:) ! Tendency flux (kg/m²/s)
real(fp), intent(in) :: dt
real(fp), intent(in), optional :: layer_height
integer, intent(out) :: rc
real(fp), pointer :: chem_column(:), emis_column(:)
real(fp) :: height
integer :: k
rc = cc_success
height = 50.0_fp ! Default surface layer height
if (present(layer_height)) height = layer_height
! Get pointers to current column data
chem_column => this%get_chem_column_ptr(species_name)
emis_column => this%get_emis_column_ptr(species_name)
if (.not. associated(chem_column) .or. .not. associated(emis_column)) then
print *, 'ERROR: Could not get column pointers for ', trim(species_name)
rc = cc_failure
return
endif
! Get chemistry state for species metadata
! Real implementation would use this%chem_state directly
! For now, skip this step
! Apply tendency to each vertical level
do k = 1, this%nlev
! Apply tendency directly to chemistry column
chem_column(k) = chem_column(k) + tendency_column(k) * dt
! Accumulate in emissions for diagnostics
emis_column(k) = emis_column(k) + tendency_column(k)
end do
end subroutine column_view_apply_tendency
!========================================================================
!! Cleanup column view
!========================================================================
subroutine column_view_cleanup(this)
class(ColumnViewType), intent(inout) :: this
! Nullify pointers
this%met_state => null()
this%chem_state => null()
this%met_column => null()
this%chem_column => null()
this%emis_column => null()
end subroutine column_view_cleanup
!========================================================================
!! Convenience function to create column view
!========================================================================
function create_column_view(met_state, chem_state) result(col_view)
type(MetStateType), intent(in), target, optional :: met_state
type(ChemStateType), intent(in), target, optional :: chem_state
type(ColumnViewType) :: col_view
integer :: rc
call col_view%init(met_state, chem_state, rc)
if (rc /= cc_success) then
print *, 'WARNING: Failed to initialize column view'
endif
end function create_column_view
!========================================================================
! ColumnProcessorType Implementation
!========================================================================
subroutine processor_init(this, max_columns, rc)
class(ColumnProcessorType), intent(inout) :: this
integer, intent(in) :: max_columns
integer, intent(out) :: rc
rc = cc_success
allocate(this%columns(max_columns))
this%n_columns = 0
this%current_column = 1
end subroutine processor_init
subroutine processor_add_column(this, virtual_col, rc)
class(ColumnProcessorType), intent(inout) :: this
type(VirtualColumnType), intent(in) :: virtual_col
integer, intent(out) :: rc
rc = cc_success
if (this%n_columns >= size(this%columns)) then
rc = cc_failure
return
endif
this%n_columns = this%n_columns + 1
this%columns(this%n_columns) = virtual_col
end subroutine processor_add_column
subroutine processor_process_all(this, process_proc, rc)
class(ColumnProcessorType), intent(inout) :: this
procedure(column_process_interface) :: process_proc
integer, intent(out) :: rc
integer :: i, local_rc
rc = cc_success
do i = 1, this%n_columns
call process_proc(this%columns(i), local_rc)
if (local_rc /= cc_success) then
rc = local_rc
! Continue processing other columns or exit based on error policy
endif
enddo
end subroutine processor_process_all
function processor_get_column(this, index) result(column)
class(ColumnProcessorType), intent(in) :: this
integer, intent(in) :: index
type(VirtualColumnType) :: column
if (index >= 1 .and. index <= this%n_columns) then
column = this%columns(index)
endif
end function processor_get_column
function processor_get_current_column(this) result(column)
class(ColumnProcessorType), intent(in) :: this
type(VirtualColumnType) :: column
column = this%get_column(this%current_column)
end function processor_get_current_column
subroutine processor_next_column(this, rc)
class(ColumnProcessorType), intent(inout) :: this
integer, intent(out) :: rc
rc = cc_success
if (this%current_column < this%n_columns) then
this%current_column = this%current_column + 1
else
rc = cc_failure ! No more columns
endif
end subroutine processor_next_column
subroutine processor_reset(this)
class(ColumnProcessorType), intent(inout) :: this
this%current_column = 1
end subroutine processor_reset
subroutine processor_cleanup(this)
class(ColumnProcessorType), intent(inout) :: this
integer :: i
if (allocated(this%columns)) then
do i = 1, this%n_columns
call this%columns(i)%cleanup()
enddo
deallocate(this%columns)
endif
this%n_columns = 0
end subroutine processor_cleanup
end module columninterface_mod