Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull UDUNITS fortran interface into develop #2934

Merged
merged 3 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Added Fortran interface to UDUNITS2
- Improve mask sampler by adding an MPI step and a LS_chunk (intermediate step)
- Update Baselibs in CI to 7.25.0
- NOTE: The docker image also updates to Intel 2024.2 and Intel MPI 2021.13
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ add_subdirectory (base)
add_subdirectory (MAPL)
add_subdirectory (gridcomps)
add_subdirectory (griddedio)
add_subdirectory (udunits2f)
if (BUILD_WITH_FARGPARSE)
add_subdirectory (docs)
add_subdirectory (benchmarks)
Expand Down
68 changes: 68 additions & 0 deletions cmake/Findudunits.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# (C) Copyright 2022- UCAR.
#
# Try to find the udunits headers and library
#
# This module defines:
#
# - udunits::udunits - The udunits shared library and include directory, all in a single target.
# - udunits_FOUND - True if udunits was found
# - udunits_INCLUDE_DIR - The include directory
# - udunits_LIBRARY - The library
# - udunits_LIBRARY_SHARED - Whether the library is shared or not
# - udunits_XML_PATH - path to udunits2.xml
#
# The following paths will be searched in order if set in CMake (first priority) or environment (second priority):
#
# - UDUNITS2_INCLUDE_DIRS & UDUNITS2_LIBRARIES - folders containing udunits2.h and libudunits2, respectively.
# - UDUNITS2_ROOT - root of udunits installation
# - UDUNITS2_PATH - root of udunits installation
#
# Notes:
# - The hint variables are capitalized because this is how they are exposed in the jedi stack.
# See https://github.com/JCSDA-internal/jedi-stack/blob/develop/modulefiles/compiler/compilerName/compilerVersion/udunits/udunits.lua for details.

find_path (
udunits_INCLUDE_DIR
udunits2.h
HINTS ${UDUNITS2_INCLUDE_DIRS} $ENV{UDUNITS2_INCLUDE_DIRS}
${UDUNITS2_ROOT} $ENV{UDUNITS2_ROOT}
${UDUNITS2_PATH} $ENV{UDUNITS2_PATH}
PATH_SUFFIXES include include/udunits2
DOC "Path to udunits2.h" )

find_file (
udunits_XML_PATH
udunits2.xml
HINTS ${UDUNITS2_XML_PATH} $ENV{UDUNITS2_XML_PATH}
${UDUNITS2_ROOT} $ENV{UDUNITS2_ROOT}
${UDUNITS2_PATH} $ENV{UDUNITS2_PATH}
PATH_SUFFIXES share share/udunits
DOC "Path to udunits2.xml" )

find_library(udunits_LIBRARY
NAMES udunits2 udunits
HINTS ${UDUNITS2_LIBRARIES} $ENV{UDUNITS2_LIBRARIES}
${UDUNITS2_ROOT} $ENV{UDUNITS2_ROOT}
${UDUNITS2_PATH} $ENV{UDUNITS2_PATH}
PATH_SUFFIXES lib64 lib
DOC "Path to libudunits library" )

# We need to support both static and shared libraries
if (udunits_LIBRARY MATCHES ".*\\.a$")
set(udunits_LIBRARY_SHARED FALSE)
else()
set(udunits_LIBRARY_SHARED TRUE)
endif()

include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (udunits DEFAULT_MSG udunits_LIBRARY udunits_INCLUDE_DIR udunits_XML_PATH)

mark_as_advanced (udunits_LIBRARY udunits_INCLUDE_DIR udunits_XML_PATH)

if(udunits_FOUND AND NOT TARGET udunits::udunits)
add_library(udunits::udunits INTERFACE IMPORTED)
set_target_properties(udunits::udunits PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${udunits_INCLUDE_DIR})
set_target_properties(udunits::udunits PROPERTIES INTERFACE_LINK_LIBRARIES ${udunits_LIBRARY})
set_property(TARGET udunits::udunits APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
endif()

28 changes: 28 additions & 0 deletions udunits2f/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
esma_set_this (OVERRIDE udunits2f)

set(srcs
CptrWrapper.F90
UDSystem.F90
udunits2f.F90
encoding.F90
interfaces.F90
status_codes.F90
ut_set_ignore_error_message_handler.c
)
list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")

esma_add_library(${this}
SRCS ${srcs}
TYPE SHARED
)

find_package(udunits REQUIRED)
find_package(EXPAT REQUIRED)

target_link_libraries(${this} PUBLIC udunits::udunits)
target_link_libraries(${this} PUBLIC EXPAT::EXPAT)

if (PFUNIT_FOUND)
# Turning off until test with GNU can be fixed
add_subdirectory(tests EXCLUDE_FROM_ALL)
endif ()
64 changes: 64 additions & 0 deletions udunits2f/CptrWrapper.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module ud2f_CptrWrapper
use, intrinsic :: iso_c_binding, only: c_ptr, C_NULL_PTR, c_associated
implicit none
private

public :: CptrWrapper

!================================ CPTRWRAPPER ==================================
! Base class to wrap type(c_ptr) instances used for udunits2 objects that cannot
! interface directly to fortran. Each extended class must provide a subroutine
! to free the memory associated with cptr_
type, abstract :: CptrWrapper
private
type(c_ptr) :: cptr_ = C_NULL_PTR
contains
procedure :: get_cptr
procedure :: set_cptr
procedure :: is_free
procedure :: free
procedure(I_free_memory), deferred :: free_memory
end type CptrWrapper

abstract interface

subroutine I_free_memory(this)
import :: CptrWrapper
class(CptrWrapper), intent(in) :: this
end subroutine I_Free_Memory

end interface

contains

type(c_ptr) function get_cptr(this)
class(CptrWrapper), intent(in) :: this

get_cptr = this%cptr_

end function get_cptr

subroutine set_cptr(this, cptr)
class(CptrWrapper), intent(inout) :: this
type(c_ptr), intent(in) :: cptr
this%cptr_ = cptr
end subroutine set_cptr

logical function is_free(this)
class(CptrWrapper), intent(in) :: this

is_free = .not. c_associated(this%cptr_)

end function is_free

! Free up memory pointed to by cptr_ and set cptr_ to c_null_ptr
subroutine free(this)
class(CptrWrapper), intent(inout) :: this

if(this%is_free()) return
call this%free_memory()
this%cptr_ = c_null_ptr

end subroutine free

end module ud2f_CptrWrapper
Loading