Skip to content
This repository has been archived by the owner on Aug 20, 2020. It is now read-only.

Commit

Permalink
Merge pull request #11 from MeteoSwiss-APN/master
Browse files Browse the repository at this point in the history
Push latest changes from MCH-APN for a 0.2 release
  • Loading branch information
clementval authored Oct 6, 2016
2 parents 53c5c84 + 3f6855e commit 3e72b49
Show file tree
Hide file tree
Showing 43 changed files with 1,341 additions and 1,045 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
build
install
buildenv
18 changes: 14 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cmake_minimum_required( VERSION 2.8 )
# able to change.
SET(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/" CACHE PATH "installation prefix")

project( SerialBox )
project( Serialbox )
enable_language (Fortran)
find_package( Boost )

Expand All @@ -23,9 +23,16 @@ set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran )

install(DIRECTORY ${CMAKE_BINARY_DIR}/fortran/ DESTINATION include/fortran FILES_MATCHING PATTERN "*.mod" PATTERN "CMake*" EXCLUDE )

set(CXX11_FLAGS "-std=c++11")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# Based on http://stackoverflow.com/a/31010221/592024
if (CMAKE_VERSION VERSION_LESS "3.1")
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Cray")
set (CMAKE_CXX_FLAGS "-h std=c++11 ${CMAKE_CXX_FLAGS}")
else()
set (CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}")
endif()
else()
set (CMAKE_CXX_STANDARD 11)
endif()

function(serialbox_add_test test_name )
#ignore the execute prefix in case it is not a valid executable prefix
Expand Down Expand Up @@ -59,6 +66,9 @@ endif ()
# Python installation path
set (PYTHON_PATH "python")

# Add boost include dir to includes:
include_directories(${Boost_INCLUDE_DIR})

# Build sources
add_subdirectory( libs/libjson )
add_subdirectory( libs/sha256 )
Expand Down
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Next release
* SerialBox changed to Serialbox everywhere
* Handle execution with multiple MPI processes with an mpi_rank option for
the !$ser init directive

# Release 0.1.1
* Bug fix for BOOST_STATIC_ASSERT

Expand Down
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,41 @@

# Introduction

The SerialBox is a set of tools around serialization / deserialization of data.
The Serialbox is a set of tools around serialization / deserialization of data.
The box is used in several projects for building validation frameworks against reference runs.
This is useful in the scope of rewrite of large codes, or when porting codes to multiple computing architectures.
As an example, porting scientific codes to graphical processing units, that require continuous validation against the existing x86 code.

# Structure

* src/ : It the main core of the SerialBox, written in C++, which provides
* src/ : It the main core of the Serialbox, written in C++, which provides
* C++ functionality that can be used to serialize data from a reference run.
* Interfaces for deserializing into memory data structures
* Control the metadata of the fields being serialized/deserialized.
* src/utils: logger and other C++ utilities
* wrapper: a C wrapper that allows to interoperate the core C++ functionality from other languages like Fortran
* doc/ : latex documentation, tutorials and presentations
* [python/](python/README.md) : contains various python tools based on the SerialBox format, namely
* pp_ser: a tiny DSL/parser that facilitates inserting SerialBox statements into your Fortran Code.
* [python/](python/README.md) : contains various python tools based on the Serialbox format, namely
* pp_ser: a tiny DSL/parser that facilitates inserting Serialbox statements into your Fortran Code.
* Visualizer: a python tool that helps visualizing serialized data
* tools/ : various tools used to validation, dumping, converting or comparing of multiple serialized runs, etc.
* fortran/ : fortran interfaces to the SerialBox C++ functionality
* fortran/ : fortran interfaces to the Serialbox C++ functionality

# Building

simply ```mkdir build; cd build; cmake ../; make [install]```

for building the documentation ```make doc```

## CSCS Environment

On daint, greina, kesch and lema a Serialbox installation is provided by jenkins (daily checkout of MeteoSwiss-APN master). If you want to compile and install Serialbox manually you can do so using the build environment.

Go to your checkout of Serialbox, then execute:

git clone [email protected]:C2SM-RCM/buildenv.git
./buildenv/package_builder/build_apkg.sh -p serialbox -d . --local -c $COMPILER

This will build and install serialbox into the `./install` folder with the compiler `$COMPILER` (usually gnu or cray). If the `-c $COMPILER` option is omitted the script will build against all available targets.

Refer to the script for further configuration options.
62 changes: 23 additions & 39 deletions doc/pp_ser/ppser_doc.tex
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,46 @@ \subsection{\texttt{INIT}}
Initialize the serialization framework.

\begin{lstlisting}
!$ser init directory=dir prefix=pre [mode=] [prefix_ref=] [if if_statement]
!$ser init directory=dir prefix=pre [mode=] [prefix_ref=] [mpi_rank=] [rprecision=] [rperturb=] [realtype=] [if if_statement]
\end{lstlisting}

\begin{itemize}
\item \texttt{dir}: the directory of the main database
\item \texttt{prefix}: the prefix of the main database file names
\item \texttt{mode}: 0 or 1
\item \texttt{prefix\_ref}: the prefix of the reference database file names. If reference database is set, the serializer reads from the reference database and writes to the main database.
\item \texttt{mpi\_rank}: the MPI rank (optional). If the MPI rank is set, database files will be suffixed with it.
\item \texttt{rprecision}: specify the precision for the perturbation.
\item \texttt{rperturb}: specify the desired magnitude of perturbation.
\item \texttt{realtype}: specify the size of the real type with an integer value.
\item \texttt{if\_statement}: under which condition is the directive executed
\end{itemize}

Examples:
\begin{lstlisting}
!$ser init directory='.' prefix='Field'
!$ser init directory='.' prefix='Field' mpi_rank=my_cart_id
!$ser init directory='.' prefix='database' prefix_ref='ref_database'
!$ser init directory='.' prefix='Field' if ser_test_mode==0
\end{lstlisting}

\begin{lstlisting}
REAL(KIND=8) :: rprecision
rprecision = 10.0**(-PRECISION(1.0))

!$ser init directory='.' prefix='SerialboxTest-output' &
!$ser prefix_ref='SerialboxTest' rprecision=rprecision &
!$ser rperturb=1.0e-5_8
\end{lstlisting}

\subsection{\texttt{MODE}}
Set the serialization mode (\texttt{ppser\_mode}). 0 = write, 1 = read. \texttt{ppser\_mode} is by default 0.
Set the serialization mode (\texttt{ppser\_mode}). 0 = write, 1 = read, 2 = read with perturbation. \texttt{ppser\_mode} is by default 0.

\begin{lstlisting}
!$ser mode [[read | write] | [0 | 1] | variable] [if if_statement]
!$ser mode [[read | write | read-perturb] | [0 | 1] | variable] [if if_statement]
\end{lstlisting}

When the mode \lstinline!read-perturb! is used, the initialization must be made with \lstinline!rprecision! and \lstinline!rperturb! values.

Examples:
\begin{lstlisting}
!$ser mode 0
Expand All @@ -97,26 +112,13 @@ \subsection{\texttt{DATA}}
Serialize the data field.

\begin{lstlisting}
!$ser data field=variable [field2=variable2 ...] [removeintentin] [if if_statement]
\end{lstlisting}

If \texttt{removeintentin} is stated, \ppser{} will find the declarations of all the variables in that directive and remove \texttt{INTENT(IN)}:
\begin{lstlisting}
!$ser data pp=pp(:) removeintentin
\end{lstlisting}
is translated to
\begin{lstlisting}
#ifdef SERIALIZE
REAL(wp) :: pp(kbdim)
#else
REAL(wp), INTENT (IN) :: pp(kbdim)
#endif
!$ser data field=variable [field2=variable2 ...] [if if_statement]
\end{lstlisting}

Examples:
\begin{lstlisting}
!$ser data pt=pt(:,kk) pq=pq(:,kk)
!$ser data pp=pp(:) removeintentin
!$ser data pp=pp(:)
!$ser data pp_field=pp pq=pq if test_counter<30
\end{lstlisting}

Expand All @@ -128,7 +130,7 @@ \subsection{\texttt{ACCDATA}}
Examples:
\begin{lstlisting}
!$ser accdata pt=pt(:,kk) pq=pq(:,kk)
!$ser data pp=pp(:) removeintentin
!$ser data pp=pp(:)
\end{lstlisting}

\subsection{\texttt{VERBATIM}}
Expand Down Expand Up @@ -195,7 +197,7 @@ \subsection{A first example}
!$ser savepoint cuadjtq.DoStep-in
!$ser mode write
!$ser data pt=pt(:,kk) pq=pq(:,kk)
!$ser data pp=pp(:) removeintentin
!$ser data pp=pp(:)

ACC_PREFIX PARALLEL, IF (i_am_accel_node)
...
Expand Down Expand Up @@ -294,23 +296,5 @@ \subsection{Reference database}

If \texttt{ser\_test\_mode} is 0, we are generating the reference database. If it is 1, we are generating the test database.

\subsection{Multiple MPI nodes}
When we are running on multiple MPI nodes, we do not want the serializer to write to the same database. To solve this, we add the MPI rank to the prefix of the database.
\begin{lstlisting}
MODULE mo_cuadjust
!$ser verbatim USE mo_mpi, ONLY: get_my_global_mpi_id
IMPLICIT NONE
SUBROUTINE cuadjtq()
!get mpi rank
!$ser verbatim mpi_id = get_my_global_mpi_id()
!$ser verbatim Write( str_prefix, '(I1)' ) mpi_id
!$ser verbatim str_prefix = 'rank'//trim(str_prefix)//'_field'

!initialize the serialization framework
!$ser init directory='.' prefix='ref_'//str_prefix

END SUBROUTINE cuadjtq
END module mo_cuadjust
\end{lstlisting}

\end{document}
75 changes: 75 additions & 0 deletions examples/perturbation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(PERTURB_SERIALBOX_FORTRAN_SAMPLE NONE)
ENABLE_LANGUAGE(Fortran)

set(SERIALBOX_DIR "${CMAKE_SOURCE_DIR}/../../install/")
set(SERIALBOXI "${SERIALBOX_DIR}/${COMPILER}/include/SerialBox/")
set(SERIALBOXL "${SERIALBOX_DIR}/lib")
SET(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -cpp -ffree-form -ffree-line-length-180 -J.")
add_definitions(-DSERIALIZE)

file(MAKE_DIRECTORY pp)

include_directories(${SERIALBOXI})
include_directories("${SERIALBOX_DIR}/include/fortran")
link_directories(${SERIALBOXL})

set(
PERTURB_SAMPLE_SOURCES
"m_ser.f90"
"main_producer.f90"
"main_consumer.f90"
"main_consumer_perturb.f90"
)

# generate preprocessed files with pp_ser
ADD_CUSTOM_COMMAND(
OUTPUT pp/m_ser.f90 pp/main_consumer.f90 pp/main_consumer_perturb.f90 pp/main_producer.f90
COMMAND ${CMAKE_SOURCE_DIR}/../../python/pp_ser.py -d pp ${CMAKE_SOURCE_DIR}/m_ser.f90
COMMAND ${CMAKE_SOURCE_DIR}/../../python/pp_ser.py -d pp ${CMAKE_SOURCE_DIR}/main_consumer.f90
COMMAND ${CMAKE_SOURCE_DIR}/../../python/pp_ser.py -d pp ${CMAKE_SOURCE_DIR}/main_consumer_perturb.f90
COMMAND ${CMAKE_SOURCE_DIR}/../../python/pp_ser.py -d pp ${CMAKE_SOURCE_DIR}/main_producer.f90
DEPENDS m_ser.f90 main_consumer.f90 main_consumer_perturb.f90 main_producer.f90
)

ADD_EXECUTABLE(
main_producer
pp/m_ser.f90
pp/main_producer.f90
)

ADD_EXECUTABLE(
main_consumer
pp/m_ser.f90
pp/main_consumer.f90
)

ADD_EXECUTABLE(
main_consumer_perturb
pp/m_ser.f90
pp/main_consumer_perturb.f90
)

target_link_libraries(main_producer FortranSer.a)
target_link_libraries(main_producer SerialboxWrapper.a)
target_link_libraries(main_producer Serialbox.a)
target_link_libraries(main_producer Utils.a)
target_link_libraries(main_producer sha256.a)
target_link_libraries(main_producer json.a)
target_link_libraries(main_producer stdc++)

target_link_libraries(main_consumer FortranSer.a)
target_link_libraries(main_consumer SerialboxWrapper.a)
target_link_libraries(main_consumer Serialbox.a)
target_link_libraries(main_consumer Utils.a)
target_link_libraries(main_consumer sha256.a)
target_link_libraries(main_consumer json.a)
target_link_libraries(main_consumer stdc++)

target_link_libraries(main_consumer_perturb FortranSer.a)
target_link_libraries(main_consumer_perturb SerialboxWrapper.a)
target_link_libraries(main_consumer_perturb Serialbox.a)
target_link_libraries(main_consumer_perturb Utils.a)
target_link_libraries(main_consumer_perturb sha256.a)
target_link_libraries(main_consumer_perturb json.a)
target_link_libraries(main_consumer_perturb stdc++)
24 changes: 24 additions & 0 deletions examples/perturbation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Serialbox Fortran example

This small example shows how to use Serialbox in a Fortran code using the
serialization directives.

The serialization happens in the `m_ser.f90` module. Two small programs use
this module to serialize and deserialize data.


It is important to use the same Fortran compiler than the one used to build
Serialbox.

### Build the example
```bash
cmake .
make
```

### Run the example
```bash
./main_producer
./main_consumer
./main_consumer_perturb
```
44 changes: 44 additions & 0 deletions examples/perturbation/m_ser.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
MODULE m_ser

IMPLICIT NONE

CONTAINS

SUBROUTINE serialize(a)
IMPLICIT NONE
REAL(KIND=8), DIMENSION(:,:,:) :: a

!$ser init directory='.' prefix='SerialboxTest'
!$ser savepoint sp1
!$ser mode write
!$ser data ser_a=a

END SUBROUTINE serialize

SUBROUTINE deserialize(a)
IMPLICIT NONE
REAL(KIND=8), DIMENSION(:,:,:) :: a

!$ser init directory='.' prefix='SerialboxTest-output' prefix_ref='SerialboxTest'
!$ser savepoint sp1
!$ser mode read
!$ser data ser_a=a
!$ser mode write
!$ser data ser_a=a

END SUBROUTINE deserialize

SUBROUTINE deserialize_with_perturb(a)
IMPLICIT NONE
REAL(KIND=8), DIMENSION(:,:,:) :: a
REAL(KIND=8) :: rprecision
rprecision = 10.0**(-PRECISION(1.0))

!$ser init directory='.' prefix='SerialboxTest-output' prefix_ref='SerialboxTest' rprecision=rprecision rperturb=1.0e-5_8
!$ser savepoint sp1
!$ser mode read-perturb
!$ser data ser_a=a

END SUBROUTINE deserialize_with_perturb

END MODULE m_ser
10 changes: 10 additions & 0 deletions examples/perturbation/main_consumer.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PROGRAM main_consumer
USE m_ser
IMPLICIT NONE
REAL(KIND=8), DIMENSION(5,5,5) :: a

a = 0.0
PRINT*,'Before read from serializer: sum(a)=', sum(a)
CALL deserialize(a)
PRINT*,'After read from serializer: sum(a)=', sum(a)
END PROGRAM main_consumer
10 changes: 10 additions & 0 deletions examples/perturbation/main_consumer_perturb.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PROGRAM main_consumer_perturb
USE m_ser
IMPLICIT NONE
REAL(KIND=8), DIMENSION(5,5,5) :: a

a = 0.0
PRINT*,'Before read from serializer: sum(a)=', sum(a)
CALL deserialize_with_perturb(a)
PRINT*,'After read from serializer: sum(a)=', sum(a)
END PROGRAM main_consumer_perturb
9 changes: 9 additions & 0 deletions examples/perturbation/main_producer.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
PROGRAM main_producer
USE m_ser
IMPLICIT NONE
REAL(KIND=8), DIMENSION(5,5,5) :: a

a = 5.0
PRINT *, 'CALL serialize with sum(a)=', sum(a)
CALL serialize(a)
END PROGRAM main_producer
Loading

0 comments on commit 3e72b49

Please sign in to comment.