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

Add Fortran Interface for NetCDF C++ API: File Create and Close Operations #28

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
28866ea
Added pFUnit as an optional dependency for building and writing unit …
amstokely Nov 14, 2024
62bcdbb
Updated the find libbufr command in the ncep bufr install section.
amstokely Nov 14, 2024
b1e6038
Updated installation section in README
amstokely Nov 14, 2024
99f44a2
Udated installation section of README.
amstokely Nov 14, 2024
076669b
Fixed typo in install instructions
amstokely Nov 14, 2024
21e5b49
Fixed bug in install instructions.
amstokely Nov 14, 2024
69a42e8
Added a dummy pFUnit test.
amstokely Nov 14, 2024
9e12546
Updated unit test example.
amstokely Nov 14, 2024
62eeb94
Updated example unit test.
amstokely Nov 14, 2024
8d0195f
Updated example test documentation.
amstokely Nov 14, 2024
a7dea9a
Fixed logic for determing which set_obserr subroutine to call in ncio…
amstokely Nov 11, 2024
11ff00a
Add derived types for Fortran/C interoperability with non-scalar types.
amstokely Nov 18, 2024
714eabe
Added check to add_memcheck_ctest function to check if valgrind is in…
amstokely Nov 18, 2024
e813773
Checking out main.
amstokely Nov 18, 2024
6a2b0bf
Reverted netcdf_mod.f90 to it's original form.
amstokely Nov 18, 2024
101e9c6
Implemented netcdf c++ wrapper api that can easily be interfaced with…
amstokely Nov 26, 2024
efcacda
Finished fortran interface and tests for all addVar, addDim, create/c…
amstokely Nov 27, 2024
98e08e4
Finished functional tests for C++ and Fortran netcdf code.
amstokely Nov 30, 2024
58c3370
Deleted netcdf_c.h
amstokely Nov 30, 2024
b656936
Added new netcdf calls to ncio mod.
amstokely Dec 2, 2024
01063fa
Impl side by side netcdf IO using the new C++ interface in ncio_mod.f90
amstokely Dec 3, 2024
80491f5
Added ioda dimension name map to map old dim names to new ioda3 dim n…
amstokely Dec 3, 2024
552d7a9
Fixed add dim bug.
amstokely Dec 3, 2024
e09a6ef
Renamed netcdf_c modules/files to netcdf_cxx.
amstokely Dec 3, 2024
68d936d
Fixed string fill bug.
amstokely Dec 3, 2024
0d8117a
Removed satwind integration test as it is to large/broadspectrum test…
amstokely Dec 3, 2024
7cb1034
Moved FindNetCDF and Obs2Ioda_Functions cmake files into the same dir…
amstokely Dec 3, 2024
a90461e
Created C++ netcdf interface for opening and closing netcdf files usi…
amstokely Dec 4, 2024
23fdad0
Removed pfunit dep and migrated fortran unit tests to pure fortran. A…
amstokely Dec 11, 2024
f8f9060
Changed minimum required version of cmake.
amstokely Dec 11, 2024
34f7758
Removed pfunit fortran dir.
amstokely Dec 12, 2024
00e02ab
Rebased off feature/c_string_interpol
amstokely Dec 12, 2024
8fe71a8
Deleted old ufo_variables_mod.F90 file.
amstokely Dec 12, 2024
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
23 changes: 18 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Check CMake version
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.12)

include("${CMAKE_SOURCE_DIR}/cmake/Functions/Obs2Ioda_Functions.cmake")
include("${CMAKE_SOURCE_DIR}/cmake/Obs2Ioda_Functions.cmake")
# Define the project
project(obs2ioda LANGUAGES Fortran)
project(obs2ioda LANGUAGES Fortran C CXX)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# Fortran module output directory for build interface
set(OBS2IODA_MODULE_DIR ${PROJECT_NAME}/module/${CMAKE_Fortran_COMPILER_ID}/${CMAKE_Fortran_COMPILER_VERSION})
Expand All @@ -15,9 +15,22 @@ install(DIRECTORY ${CMAKE_BINARY_DIR}/${OBS2IODA_MODULE_DIR}/ DESTINATION ${CMAK

# Set the Fortran compiler and flags
set(NCEP_BUFR_LIB CACHE STRING "" )
# Set to ON to build tests. Default is OFF. If testing is enabled,
set(BUILD_TESTS CACHE BOOL OFF)

# Find required packages
find_package(NetCDF REQUIRED COMPONENTS Fortran C)
find_package(NetCDF REQUIRED COMPONENTS Fortran CXX C)

add_subdirectory("${CMAKE_SOURCE_DIR}/obs2ioda-v2")

if (BUILD_TESTS)
enable_testing()
INCLUDE(FetchContent)
FETCHCONTENT_DECLARE(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
FETCHCONTENT_MAKEAVAILABLE(googletest)
add_subdirectory("${CMAKE_SOURCE_DIR}/test")
endif ()

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ File types that obs2ioda can handle:
* HS_H08_YYYYMMDD_HH00_BNN_FLDK_R20_S0210.DAT
* OR_ABI-L1b-Rad nc files

## See [obs2ioda-v1/README.md](https://github.com/jamiebresch/obs2ioda/blob/main/obs2ioda-v1/README.md) for compilation and usage.
## See [obs2ioda-v1/README.md](https://github.com/NCAR/obs2ioda/blob/main/obs2ioda-v1/README.md) for compilation and usage.

## See [obs2ioda-v2/README.md](https://github.com/jamiebresch/obs2ioda/blob/main/obs2ioda-v2/README.md) for compilation and usage.
## See [obs2ioda-v2/README.md](https://github.com/NCAR/obs2ioda/blob/main/obs2ioda-v2/README.md) for compilation and usage.

## See [goes_abi/README.md](https://github.com/jamiebresch/obs2ioda/blob/main/goes_abi/README.md) for compilation and usage.
## See [goes_abi/README.md](https://github.com/NCAR/obs2ioda/blob/main/goes_abi/README.md) for compilation and usage.

## Observation data sources:
* https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/
Expand Down
File renamed without changes.
30 changes: 0 additions & 30 deletions cmake/Functions/Obs2Ioda_Functions.cmake

This file was deleted.

31 changes: 31 additions & 0 deletions cmake/Obs2Ioda_CompilerFlags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Set Fortran compiler flags specific to the GNU Compiler
# -ffree-line-length-none: Remove the limit on the length of lines in the source file
# -mcmodel=medium: Allow for larger datasets in memory
set(FORTRAN_COMPILER_GNU_FLAGS
$<$<COMPILE_LANGUAGE:Fortran>:-ffree-line-length-none -mcmodel=medium>
)

# Set Debugging Fortran compiler flags specific to the GNU Compiler
# -fbacktrace: Provide a backtrace when an error occurs
# -ffpe-trap=invalid,zero,overflow: Trap floating point exceptions (invalid calculation, divide by zero, overflow)
# -fcheck=all: Execute all types of runtime checks
# -g: Produce debugging information
set(FORTRAN_COMPILER_GNU_DEBUG_FLAGS
$<$<COMPILE_LANGUAGE:Fortran>:-g -fbacktrace -ffpe-trap=invalid,zero,overflow -fcheck=all>
)

# Set Fortran compiler flags for the Intel Compiler
# -mcmodel=medium: Allow for larger datasets in memory
set(FORTRAN_COMPILER_INTEL_FLAGS
$<$<COMPILE_LANGUAGE:Fortran>:-mcmodel=medium>
)

# Set Debugging Fortran compiler flags for the Intel Compiler
# -check uninit: Checks uninitialized variables
# -ftrapuv: Enable trapping of uninitialized variables
# -g: Enable production of debug information
# -traceback: Give symbolic traceback on errors
# -fpe0: Stop execution when a floating-point exception occurs
set(FORTRAN_COMPILER_INTEL_DEBUG_FLAGS
$<$<COMPILE_LANGUAGE:Fortran>:-check uninit -ftrapuv -g -traceback -fpe0>
)
108 changes: 108 additions & 0 deletions cmake/Obs2Ioda_Functions.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
include(${CMAKE_SOURCE_DIR}/cmake/Obs2Ioda_CompilerFlags.cmake)

function(obs2ioda_fortran_library target)
set_target_properties(${target} PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/${OBS2IODA_MODULE_DIR})
target_include_directories(${target} INTERFACE $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/${OBS2IODA_MODULE_DIR}>
$<INSTALL_INTERFACE:${OBS2IODA_MODULE_DIR}>)
#Relocatable, portable, runtime dynamic linking
set_target_properties(${target} PROPERTIES INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
# Global Fortran configuration
set(public_link_libraries_name ${target}_PUBLIC_LINK_LIBRARIES)
set(public_link_libraries ${${public_link_libraries_name}})
set_target_properties(${target} PROPERTIES Fortran_FORMAT FREE)

# Compiler-specific options and flags
set(OBS2IODA_FORTRAN_TARGET_COMPILE_OPTIONS_PRIVATE
$<$<COMPILE_LANGUAGE:Fortran>:-mcmodel=medium>
)
if (CMAKE_Fortran_COMPILER_ID MATCHES GNU)
list(APPEND OBS2IODA_FORTRAN_TARGET_COMPILE_OPTIONS_PRIVATE
${FORTRAN_COMPILER_GNU_FLAGS}
)
if (CMAKE_BUILD_TYPE MATCHES Debug)
list(APPEND OBS2IODA_FORTRAN_TARGET_COMPILE_OPTIONS_PRIVATE
${FORTRAN_COMPILER_GNU_DEBUG_FLAGS}
)
endif ()
elseif (CMAKE_Fortran_COMPILER_ID MATCHES Intel)
list(APPEND OBS2IODA_FORTRAN_TARGET_COMPILE_OPTIONS_PRIVATE
${FORTRAN_COMPILER_INTEL_FLAGS}
)
if (CMAKE_BUILD_TYPE MATCHES Debug)
list(APPEND OBS2IODA_FORTRAN_TARGET_COMPILE_OPTIONS_PRIVATE
${FORTRAN_COMPILER_INTEL_DEBUG_FLAGS}
)
endif ()
endif ()
target_compile_options(${target} PRIVATE ${OBS2IODA_FORTRAN_TARGET_COMPILE_OPTIONS_PRIVATE})
target_link_libraries(${target} PUBLIC ${public_link_libraries})
endfunction()

function(obs2ioda_fortran_executable target)
set_target_properties(${target} PROPERTIES INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
set(public_link_libraries_name ${target}_PUBLIC_LINK_LIBRARIES)
set(public_link_libraries ${${public_link_libraries_name}})
target_link_libraries(${target} PUBLIC ${public_link_libraries})
endfunction()

function(obs2ioda_cxx_target target)
set_target_properties(${target} PROPERTIES INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
set(public_link_libraries_name ${target}_PUBLIC_LINK_LIBRARIES)
set(public_link_libraries ${${public_link_libraries_name}})

target_link_libraries(${target} PUBLIC ${public_link_libraries})
endfunction()

# Function: add_memcheck_ctest
#
# Description:
# This function adds a memory check command as a test case in CTest
# for the given target, using the Valgrind tool. If the Valgrind
# tool is not found, it will print a message specifying that the
# memory check could not be added for the given target.
#
# The Valgrind command executed as part of the test includes options
# for full leak checking (--leak-check=full), exiting with error status
# if any leaks are detected (--error-exitcode=1), and keeping track of
# the origin of uninitialized values (--track-origins=yes).
#
# Arguments:
# target: The name of the target for which the memory check will be added.
#
# Usage:
# add_memcheck_ctest(my_target)
#
# Example:
# add_memcheck_ctest(my_executable)
#
function(add_memcheck_ctest target)
find_program(VALGRIND "valgrind")
if (VALGRIND)
message(STATUS "Valgrind found: ${VALGRIND}")
message(STATUS "Adding memory check for test: ${target}")
set(VALGRIND_COMMAND valgrind --leak-check=full --error-exitcode=1 --undef-value-errors=no)
add_test(NAME ${target}_memcheck
COMMAND ${VALGRIND_COMMAND} $<TARGET_FILE:${target}>)
else ()
message(STATUS "Valgrind not found")
message(STATUS "Memory check for test: ${target} will not be added")
endif ()
endfunction()

function(add_fortran_ctest test_name test_sources library_deps)
add_executable("Test_${test_name}" ${test_sources})
message(STATUS "Adding test: ${test_name} with sources: ${test_sources} and dependencies: ${library_deps}")
target_link_libraries("Test_${test_name}" ${library_deps})
add_test(NAME ${test_name}
COMMAND ${CMAKE_BINARY_DIR}/bin/Test_${test_name})
endfunction()

function(add_cxx_ctest name sources include_dirs library_deps)
add_executable(${name} ${sources})
target_include_directories(${name} PUBLIC ${include_dirs})
target_link_libraries(${name} PUBLIC ${library_deps})
add_test(
NAME ${name}
COMMAND ${name} --gtest_filter=*
)
endfunction()
35 changes: 29 additions & 6 deletions obs2ioda-v2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
# Set include directories
include_directories(${NetCDF_INCLUDE_DIRS} )

set(netcdf_cxx_SOURCES
netcdf_file.cc
netcdf_utils.cc
)
list(TRANSFORM netcdf_cxx_SOURCES PREPEND "src/cxx/")

# Define sources
set(v2_SOURCES
define_mod.f90
Expand All @@ -14,15 +20,32 @@ set(v2_SOURCES
netcdf_mod.f90
prepbufr_mod.f90
radiance_mod.f90
ufo_variables_mod.F90
ufo_variables_mod.f90
utils_mod.f90
f_c_string_t_mod.f90
f_c_string_1D_t_mod.f90
netcdf_cxx_i_mod.f90
netcdf_cxx_mod.f90
)
list(TRANSFORM v2_SOURCES PREPEND "src/")
list(TRANSFORM v2_SOURCES PREPEND "src/fortran/")
set(v2_MAIN_SOURCE
main.f90
)
list(TRANSFORM v2_MAIN_SOURCE PREPEND "src/")
set(v2_PUBLIC_LINK_LIBRARIES "${NetCDF_LIBRARIES}" "${NCEP_BUFR_LIB}")
list(TRANSFORM v2_MAIN_SOURCE PREPEND "src/fortran/")
set(fortran_test_framework_SOURCES
fortran_test_framework_mod.f90
)
list(TRANSFORM fortran_test_framework_SOURCES PREPEND "src/test/")
add_library(netcdf_cxx SHARED ${netcdf_cxx_SOURCES})
target_include_directories(netcdf_cxx PUBLIC ${NetCDF_INCLUDE_DIRS})
set(netcdf_cxx_PUBLIC_LINK_LIBRARIES NetCDF::NetCDF_CXX NetCDF::NetCDF_C)
obs2ioda_cxx_target(netcdf_cxx ${netcdf_cxx_SOURCES})
set(v2_PUBLIC_LINK_LIBRARIES "${NCEP_BUFR_LIB}" NetCDF::NetCDF_CXX NetCDF::NetCDF_C NetCDF::NetCDF_Fortran netcdf_cxx)
add_library(v2 SHARED ${v2_SOURCES})
obs2ioda_fortran_target(v2 ${v2_MAIN_SOURCE})

target_include_directories(v2 PUBLIC ${NetCDF_INCLUDE_DIRS})
obs2ioda_fortran_library(v2)
add_executable(obs2ioda_v2 ${v2_MAIN_SOURCE})
set(obs2ioda_v2_PUBLIC_LINK_LIBRARIES v2)
obs2ioda_fortran_executable(obs2ioda_v2)
add_library(fortran_test_framework ${fortran_test_framework_SOURCES})
obs2ioda_fortran_library(fortran_test_framework)
53 changes: 36 additions & 17 deletions obs2ioda-v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,62 @@
obs2ioda-v2 utilizes CMake as its primary build system. Follow the steps below to build the project:

### Prerequisites
Please make sure the following libraries are installed:
- NetCDF
- NCEP BUFR library. (Instructions for installing the NCEP BUFR library are provided in a subsequent section)

If you have an environment preconfigured for `mpas-jedi`, simply source that environment prior to building `obs2ioda`.
Prior to building `obs2ioda`, ensure that you have installed the following libraries:

- **CMake**: Required (version 3.12 or higher).
- **NetCDF**: Required.
- **NCEP BUFR Library**: Required.

For instructions on how to install the `NCEP BUFR` library , please refer to the respective sections:

- [Installing NCEP BUFR Library](#installing-ncep-bufr-library)

If you have an environment preconfigured for `mpas-jedi` or `mpas-bundle`, simply source that environment prior to building `obs2ioda`.

### Build Instructions
1. First, clone the repository into your preferred directory (`<OBS2IODA_ROOT_DIR>`):
```bash
git clone https://github.com/NCAR/obs2ioda.git <OBS2IODA_ROOT_DIR>
```
2. Create a new directory `build` and navigate into it:
1. Create a new directory `<OBS2IODA_BUILD_DIR>` and navigate into it:
```bash
mkdir build && cd build
mkdir <OBS2IODA_BUILD_DIR> && cd <OBS2IODA_BUILD_DIR>
```
3. Locate the NCEP BUFR library by executing the following command in the `NCEP BUFR` library's build directory:
1. Set the variable OBS2IODA_CMAKE_ARGS to include the `obs2ioda` root directory and the absolute path of the `NCEP BUFR` library:
```bash
OBS2IODA_CMAKE_ARGS="<OBS2IODA_ROOT_DIR> -DNCEP_BUFR_LIB=<NCEP_BUFR_LIB_PATH>"
```
1. If building in `Debug` mode, append the following to `OBS2IODA_CMAKE_ARGS`:
```bash
OBS2IODA_CMAKE_ARGS="${OBS2IODA_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=Debug"
```
1. If building unit tests, append the following to `OBS2IODA_CMAKE_ARGS`:
```bash
OBS2IODA_CMAKE_ARGS="${OBS2IODA_CMAKE_ARGS} -DBUILD_TESTS=ON"
```

1. Next, run CMake to configure the build.
```bash
find . -name *libbufr*
cmake <OBS2IODA_ROOT_DIR> 'echo ${OBS2IODA_CMAKE_ARGS}'
```
4. Next, run CMake to configure the build. Remember to specify the path to the NCEP BUFR library:
```bash
cmake <OBS2IODA_ROOT_DIR> -DNCEP_BUFR_LIB=<NCEP_BUFR_LIB_PATH>
```
5. Finally, build the project using this command:
1. Finally, build `obs2ioda` using `CMake`'s build tool. In this case, we use `GNU Make`, but other build tools supported by `CMake` can be used:
```bash
make
```
The `obs2ioda-v2` executable will reside in the `bin` directory within the build directory.

---
## Installing NCEP BUFR Library
### Installing NCEP BUFR Library
To install the NCEP BUFR library, follow these steps:

1. Clone the NCEP BUFR repository into a directory of your choice (`<NCEP_BUFR_ROOT_DIR>`):
```bash
git clone https://github.com/NOAA-EMC/NCEPLIBS-bufr.git <NCEP_BUFR_ROOT_DIR>
```
2. Create a new directory `build` and navigate into it:
2. Create a new directory `<NCEP_BUFR_BUILD_DIR>` and navigate into it:
```bash
mkdir build && cd build
mkdir <NCEP_BUFR_BUILD_DIR> && cd <NCEP_BUFR_BUILD_DIR>
```
3. Run CMake to configure the build (Ensure NetCDF is installed):
```bash
Expand All @@ -54,9 +70,12 @@ To install the NCEP BUFR library, follow these steps:
```
5. To locate the NCEP BUFR library, run:
```bash
find . -name *libbufr*
bash -c "find . -name *libbufr*"
```
Remember to note down the library path (`<NCEP_BUFR_LIB_PATH>`) required for the build process of `obs2ioda-v2`.

---

## caveate
NetCDF-Fortran interface does not allow reading/writing NF90_STRING, so ``station_id`` and ``variable_names`` are still written out as
``char station_id(nlocs, nstring)``
Expand Down
Loading