-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from BerkeleyLab/netcdf-read-write-example
Netcdf read/write example
- Loading branch information
Showing
4 changed files
with
285 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
program netCDF_IO | ||
use netcdf, only : & | ||
nf90_create, nf90_def_dim, nf90_def_var, nf90_enddef, nf90_put_var, nf90_inquire_dimension, & ! functions | ||
nf90_close, nf90_open, nf90_inq_varid, nf90_get_var, nf90_inquire_variable, & | ||
nf90_clobber, nf90_noerr, nf90_strerror, nf90_int, nf90_nowrite ! constants | ||
use assert_m, only : assert | ||
implicit none | ||
|
||
integer i, j | ||
integer, parameter :: ny = 12, nx = 6 | ||
integer, parameter :: data_written(*,*) = reshape([((i*j, i=1,nx), j=1,ny)], [ny,nx]) | ||
integer, allocatable :: data_read(:,:) | ||
character(len=*), parameter :: file_name = "netCDF_example.nc" | ||
|
||
call netCDF_write(file_name, data_written) | ||
call netCDF_read(file_name, data_read) | ||
|
||
call assert(all(data_written == data_read) , "netCDF_IO: all(data_written == data_read)") | ||
|
||
print *, "-----> netCDF file '" // file_name // "' written and read without error <-----" | ||
|
||
contains | ||
|
||
subroutine netCDF_write(file_name_, data_out) | ||
character(len=*), intent(in) :: file_name_ | ||
integer, intent(in) :: data_out(:,:) | ||
|
||
integer ncid, varid, x_dimid, y_dimid | ||
|
||
associate(nf_status => nf90_create(file_name_, nf90_clobber, ncid)) ! create or ovewrite file | ||
call assert(nf_status == nf90_noerr, "nf90_create(file_name, nf90_clobber, ncid) succeeds",trim(nf90_strerror(nf_status))) | ||
end associate | ||
associate(nf_status => nf90_def_dim(ncid, "x", size(data_out,2), x_dimid)) ! define x dimension & get its ID | ||
call assert(nf_status == nf90_noerr,'nf90_def_dim(ncid,"x",size(data_out,2),x_dimid) succeeds',trim(nf90_strerror(nf_status))) | ||
end associate | ||
associate(nf_status => nf90_def_dim(ncid, "y", size(data_out,1), y_dimid)) ! define y dimension & get its ID | ||
call assert(nf_status==nf90_noerr, 'nf90_def_dim(ncid,"y",size(data_out,2),y_dimid) succeeds', trim(nf90_strerror(nf_status))) | ||
end associate | ||
associate(nf_status => nf90_def_var(ncid, "data", nf90_int, [y_dimid, x_dimid], varid))!define integer 'data' variable & get ID | ||
call assert(nf_status == nf90_noerr, 'nf90_def_var(ncid,"data",nf90_int,[y_dimid,x_dimid],varid) succeds', & | ||
trim(nf90_strerror(nf_status))) | ||
end associate | ||
associate(nf_status => nf90_enddef(ncid)) ! exit define mode: tell netCDF we are done defining metadata | ||
call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_enddef(ncid)', trim(nf90_strerror(nf_status))) | ||
end associate | ||
associate(nf_status => nf90_put_var(ncid, varid, data_out)) ! write all data to file | ||
call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_put_var(ncid, varid, data_out)', trim(nf90_strerror(nf_status))) | ||
end associate | ||
associate(nf_status => nf90_close(ncid)) ! close file to free associated netCDF resources and flush buffers | ||
call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_close(ncid)', trim(nf90_strerror(nf_status))) | ||
end associate | ||
|
||
end subroutine | ||
|
||
subroutine netCDF_read(file_name_, data_in) | ||
character(len=*), intent(in) :: file_name_ | ||
integer, intent(inout), allocatable :: data_in(:,:) | ||
integer ncid, varid, data_in_rank | ||
|
||
associate( nf_status => nf90_open(file_name_, nf90_nowrite, ncid) ) ! open file with read-only acces | ||
call assert(nf_status == nf90_noerr, "nf90_open(file_name_, NF90_NOWRITE, ncid) succeeds", trim(nf90_strerror(nf_status))) | ||
end associate | ||
|
||
associate( nf_status => nf90_inq_varid(ncid, "data", varid)) ! Get data variable's ID | ||
call assert(nf_status == nf90_noerr, 'nf90_inq_varid(ncid, "data", varid) succeeds', trim(nf90_strerror(nf_status))) | ||
end associate | ||
|
||
associate(data_in_shape => get_shape(ncid, "data")) | ||
allocate(data_in(data_in_shape(1), data_in_shape(2))) | ||
end associate | ||
|
||
associate( nf_status => nf90_get_var(ncid, varid, data_in)) ! Read data | ||
call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, data_in) succeeds", trim(nf90_strerror(nf_status))) | ||
end associate | ||
|
||
end subroutine | ||
|
||
function get_shape(ncid, varname) result(array_shape) | ||
implicit none | ||
character(len=*), intent(in) :: varname | ||
integer, intent(in) :: ncid | ||
integer, allocatable :: array_shape(:) | ||
character(len=32) varid_string | ||
|
||
integer varid, dimlen, i, var_rank | ||
integer, parameter :: max_rank=15 | ||
integer,dimension(max_rank+1) :: dims, dimIds | ||
|
||
associate(nf_status => nf90_inq_varid(ncid, varname, varid)) | ||
write(varid_string, *) varid | ||
call assert(nf_status == nf90_noerr, "nf90_noerr == nf90_inq_varid(ncid, varname, varid) (" // & | ||
trim(nf90_strerror(nf_status)) // "(" // trim(varid_string)// ")") | ||
end associate | ||
associate(nf_status => nf90_inquire_variable(ncid, varid, ndims = var_rank)) | ||
call assert(nf_status == nf90_noerr, "nf90_noerr == nf90_inquire_variable(ncid, varid, ndims = var_rank) (" // & | ||
trim(nf90_strerror(nf_status)) // "(" // varname // ")") | ||
end associate | ||
associate(nf_status => nf90_inquire_variable(ncid, varid, dimids = dimIds(:var_rank))) | ||
call assert(nf_status == nf90_noerr, "nf90_noerr == nf90_inquire_variable(ncid, varid, dimids = dimIds(:var_rank))", & | ||
trim(nf90_strerror(nf_status)) // "(" // varname // ")") | ||
end associate | ||
|
||
do i=1,var_rank | ||
associate(nf_status => nf90_inquire_dimension(ncid, dimIds(i), len = dimlen)) | ||
call assert(nf_status == nf90_noerr, "nf90_noerr == nf90_inquire_dimension(ncid, dimIds(i), len = dimlen)", & | ||
trim(nf90_strerror(nf_status)) // "(" // varname // ")") | ||
end associate | ||
dims(i+1)=dimlen | ||
end do | ||
|
||
array_shape = dims(2:var_rank+1) | ||
end function | ||
|
||
end program netCDF_IO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ maintainer = "[email protected]" | |
[dependencies] | ||
assert = {git = "https://github.com/sourceryinstitute/assert", tag = "1.4.0"} | ||
sourcery = {git = "https://github.com/sourceryinstitute/sourcery", tag = "3.5.0"} | ||
netcdf-interfaces = {git = "https://github.com/LKedward/netcdf-interfaces.git"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
#!/bin/sh | ||
|
||
set -e # exit on error | ||
|
||
usage() | ||
{ | ||
echo "Inference Engine Setup Script" | ||
echo "" | ||
echo "USAGE:" | ||
echo "./setup.sh [--help|-h] | [-p|--prefix=PREFIX]" | ||
echo "" | ||
echo " --help Display this help text" | ||
echo " --prefix=PREFIX Install binary in 'PREFIX/bin'" | ||
echo " Default prefix='\$HOME/.local/bin'" | ||
echo "" | ||
} | ||
|
||
PREFIX="$HOME/.local" | ||
|
||
while [ "$1" != "" ]; do | ||
PARAM=$(echo "$1" | awk -F= '{print $1}') | ||
VALUE=$(echo "$1" | awk -F= '{print $2}') | ||
case $PARAM in | ||
-h | --help) | ||
usage | ||
exit | ||
;; | ||
-p | --prefix) | ||
PREFIX=$VALUE | ||
;; | ||
*) | ||
echo "ERROR: unknown parameter \"$PARAM\"" | ||
usage | ||
exit 1 | ||
;; | ||
esac | ||
shift | ||
done | ||
|
||
set -u # error on use of undefined variable | ||
|
||
if ! command -v brew > /dev/null ; then | ||
if ! command -v curl > /dev/null ; then | ||
echo "Please install curl and then rerun ./install.sh" | ||
exit 1 | ||
fi | ||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | ||
if [ $(uname) = "Linux" ]; then | ||
if [ -z "$PATH" ]; then | ||
PATH=/home/linuxbrew/.linuxbrew/bin/ | ||
else | ||
PATH=/home/linuxbrew/.linuxbrew/bin/:"$PATH" | ||
fi | ||
fi | ||
fi | ||
|
||
|
||
brew tap fortran-lang/fortran # required for building fpm | ||
brew install fpm cmake netcdf pkg-config coreutils # coreutils supports `realpath` below | ||
|
||
PREFIX=`realpath $PREFIX` | ||
|
||
mkdir -p build/dependencies | ||
if [ ! -d ./build/dependencies/netcdf-fortran ]; then | ||
git clone https://github.com/Unidata/netcdf-fortran.git build/dependencies/netcdf-fortran | ||
fi | ||
mkdir -p build/dependencies/netcdf-fortran/build | ||
|
||
CI=${CI:-"false"} # GitHub Actions workflows set CI=true | ||
|
||
cd build/dependencies/netcdf-fortran/build | ||
GCC_VER="12" # This should be replaced with code extracting the version number from Homebrew | ||
export FC=gfortran-${GCC_VER} CC=gcc-${GCC_VER} CXX=g++-${GCC_VER} | ||
if [ $CI = true ]; then | ||
NETCDFF_PREFIX="/usr/local" | ||
else | ||
NETCDFF_PREFIX="$PREFIX" | ||
fi | ||
NETCDF_PREFIX="`brew --prefix netcdf`" | ||
cmake .. \ | ||
-DNETCDF_C_LIBRARY="$NETCDF_PREFIX/lib" \ | ||
-DNETCDF_C_INCLUDE_DIR="$NETCDF_PREFIX/include" \ | ||
-DCMAKE_INSTALL_PREFIX="$NETCDFF_PREFIX" | ||
make -j4 | ||
sudo make install | ||
cd - | ||
|
||
GIT_VERSION=`git describe --long --dirty --all --always | sed -e's/heads\///'` | ||
NETCDF_LIB_PATH="`brew --prefix netcdf`/lib" | ||
HDF5_LIB_PATH="`brew --prefix hdf5`/lib" | ||
NETCDFF_LIB_PATH="$NETCDFF_PREFIX/lib" | ||
|
||
FPM_FLAG="-cpp -DUSE_ASSERTIONS=.true." | ||
FPM_FLAG=" $FPM_FLAG -fallow-argument-mismatch -ffree-line-length-none" | ||
FPM_FLAG=" $FPM_FLAG -DVERSION=\\\'$GIT_VERSION\\\'" | ||
FPM_FLAG=" $FPM_FLAG -L$NETCDF_LIB_PATH -L$HDF5_LIB_PATH -L$NETCDFF_LIB_PATH" | ||
FPM_FC="$FC" | ||
FPM_CC="$CC" | ||
|
||
if [ $CI = true ]; then | ||
PKG_CONFIG_PATH=`realpath ./build/pkgconfig` | ||
echo "---------------" | ||
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" | ||
echo "---------------" | ||
else | ||
PKG_CONFIG_PATH=`realpath "$PREFIX"/lib/pkgconfig` | ||
fi | ||
|
||
if [ ! -d $PKG_CONFIG_PATH ]; then | ||
mkdir -p $PKG_CONFIG_PATH | ||
fi | ||
|
||
INFERENCE_ENGINE_PC="$PKG_CONFIG_PATH/inference-engine.pc" | ||
echo "INFERENCE_ENGINE_FPM_CXX=\"$CXX\"" > $INFERENCE_ENGINE_PC | ||
echo "INFERENCE_ENGINE_FPM_CC=\"$FPM_CC\"" >> $INFERENCE_ENGINE_PC | ||
echo "INFERENCE_ENGINE_FPM_FC=\"$FPM_FC\"" >> $INFERENCE_ENGINE_PC | ||
echo "INFERENCE_ENGINE_FPM_FLAG=\"$FPM_FLAG\"" >> $INFERENCE_ENGINE_PC | ||
echo "Name: inference-engine" >> $INFERENCE_ENGINE_PC | ||
echo "Description: Inference Engine" >> $INFERENCE_ENGINE_PC | ||
echo "URL: https://github.com/berkeleylab/inference-engine" >> $INFERENCE_ENGINE_PC | ||
echo "Version: 0.1.0" >> $INFERENCE_ENGINE_PC | ||
if [ $CI = true ]; then | ||
echo "---------------" | ||
echo "cat $INFERENCE_ENGINE_PC" | ||
cat $INFERENCE_ENGINE_PC | ||
echo "---------------" | ||
fi | ||
|
||
export PKG_CONFIG_PATH | ||
RUN_FPM_SH="`realpath ./build/run-fpm.sh`" | ||
echo "#!/bin/sh" > $RUN_FPM_SH | ||
echo "#-- DO NOT EDIT -- created by inference-engine/install.sh" >> $RUN_FPM_SH | ||
echo "export PKG_CONFIG_PATH" >> $RUN_FPM_SH | ||
echo "`brew --prefix fpm`/bin/fpm \$@ --verbose \\" >> $RUN_FPM_SH | ||
echo "--profile debug \\" >> $RUN_FPM_SH | ||
echo "--c-compiler \"`pkg-config inference-engine --variable=INFERENCE_ENGINE_FPM_CC`\" \\" >> $RUN_FPM_SH | ||
echo "--compiler \"`pkg-config inference-engine --variable=INFERENCE_ENGINE_FPM_FC`\" \\" >> $RUN_FPM_SH | ||
echo "--flag \"`pkg-config inference-engine --variable=INFERENCE_ENGINE_FPM_FLAG`\"" >> $RUN_FPM_SH | ||
chmod u+x $RUN_FPM_SH | ||
if [ $CI = true ]; then | ||
echo "---------------" | ||
echo "cat $RUN_FPM_SH" | ||
cat $RUN_FPM_SH | ||
echo "---------------" | ||
fi | ||
|
||
if command -v fpm > /dev/null 2>&1; then | ||
brew tap fortran-lang/fortran | ||
brew install fpm | ||
fi | ||
|
||
echo "$RUN_FPM_SH test" | ||
$RUN_FPM_SH test | ||
|
||
echo "" | ||
echo "______________ Inference-Engine has been installed! ______________" | ||
echo "" | ||
echo "To use use or test with Inference-Engine with the Fortran Package" | ||
echo "Manager (fpm) and using the required compiler/linker flags, pass" | ||
echo "a fpm command to the build/run-fpm.sh script. For example, to" | ||
echo "run one of the provided example programs with a path of the form" | ||
echo "example/<name>.f90, enter a command of the following form at " | ||
echo "a shell command prompt:" | ||
echo "" | ||
echo "./build/run-fpm.sh run --example <name>" |