Commit a23f793c authored by LEFEBVREJP email's avatar LEFEBVREJP email
Browse files

Merge branch 'python-bindings' into 'master'

Python bindings

See merge request jap/radix!66
parents 00aeecd8 52d257f9
Pipeline #35961 passed with stages
in 15 minutes and 47 seconds
......@@ -6,3 +6,4 @@ CMakeLists.txt.user
build/
CMakeSettings.json
.vs/
.DS_Store
......@@ -15,4 +15,5 @@ TRIBITS_PACKAGE_DEFINE_DEPENDENCIES(
plot radixplot SS OPTIONAL
widgets radixwidgets SS OPTIONAL
ams radixams SS OPTIONAL
py radixpy SS OPTIONAL
)
##---------------------------------------------------------------------------##
## FindPythonLibsFromExe.cmake
## --------------------------------------------------------------------------##
# FindPythonLibsFromExe is loosely adapted from Trilinos' FindPythonInclude
#
# This module uses the Python executable (if already loaded with
# FindPythonInterp) to determine the default library and include paths if not
# already set
#
# - PYTHON_LIBRARY
# - PYTHON_INCLUDE_DIR
#
# It then calls FindPythonLibs, which will set all the other required variables,
# and set the PYTHON_XXX variables if we had trouble finding them in this script
IF(PYTHON_EXECUTABLE AND (NOT PYTHON_LIBRARY OR NOT PYTHON_INCLUDE_DIR))
# Get the Python installation prefix and version
IF(NOT EXISTS "${PYTHON_EXECUTABLE}")
MESSAGE(FATAL_ERROR "Python executable specified "
"at '${PYTHON_EXECUTABLE}' does not exist")
ENDIF()
EXECUTE_PROCESS(COMMAND
${PYTHON_EXECUTABLE} -c
"import sys; sys.stdout.write(sys.prefix + ';' + sys.version[:3])"
OUTPUT_VARIABLE PREFIX_AND_VERSION
)
LIST(GET "${PREFIX_AND_VERSION}" 0 _PY_PREFIX)
LIST(GET "${PREFIX_AND_VERSION}" 1 _PY_VERSION)
# Attempt to find the include directories
SET(_PYINC "${_PY_PREFIX}/include/python${_PY_VERSION}" )
IF(EXISTS "${_PYINC}" AND EXISTS "${_PYINC}/Python.h")
SET(PYTHON_INCLUDE_DIR ${_PYINC} CACHE FILEPATH
"Path to the Python include directory" FORCE)
MESSAGE(STATUS "Found Python include directory: ${PYTHON_INCLUDE_DIR}")
ENDIF()
# Attempt to find the library
FOREACH(_PYLIB_BASE
"${_PY_PREFIX}/lib"
"${_PY_PREFIX}/lib64"
"${_PY_PREFIX}/lib/python${_PY_VERSION}/config" )
FOREACH(SUFFIX dll dylib so a)
SET(_PYLIB "${_PYLIB_BASE}/libpython${_PY_VERSION}.${SUFFIX}")
IF(EXISTS "${_PYLIB}")
SET(PYTHON_LIBRARY ${_PYLIB} CACHE FILEPATH
"Path to the Python Library" FORCE)
MESSAGE(STATUS "Found Python library: ${PYTHON_LIBRARY}")
BREAK()
ENDIF()
ENDFOREACH()
IF(PYTHON_LIBRARY)
BREAK()
ENDIF()
ENDFOREACH()
ENDIF()
# Set the version for FindPythonLibs to match the one we found
# The PYTHON_LIBRARY and PYTHON_INCLUDE_DIR values, if set, will be used
# Otherwise, standard CMake logic will work
SET(PythonLibs_FIND_VERSION ${_PY_VERSION})
FIND_PACKAGE(PythonLibs ${ARGN})
INCLUDE(FindPackageHandleStandardArgs)
# Process REQUIRED etc.
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibs
REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS
VERSION_VAR PYTHONLIBS_VERSION_STRING)
##---------------------------------------------------------------------------##
## end of FindPythonLibsFromExe.cmake
##---------------------------------------------------------------------------##
##---------------------------------------------------------------------------##
## RadixSWIGPyModules.cmake
## --------------------------------------------------------------------------##
#
# Find required Python libraries
FIND_PACKAGE(PythonLibsFromExe REQUIRED)
#
# Find the SWIG package for language bindings
FIND_PACKAGE(SWIG REQUIRED)
#
# Ensure that PYTHON wrappers are enabled
IF (ENABLE_PYTHON_WRAPPERS)
IF (NOT DEFINED SWIG_DIR)
MESSAGE(FATAL_ERROR "SWIG not loaded.")
ENDIF()
# Load SWIG and other modules we need
INCLUDE(${SWIG_USE_FILE})
INCLUDE(CMakeParseArguments)
INCLUDE(CheckCXXCompilerFlag)
# Prepare to turn off some warnings that commonly show up in SWIG wrapper code
SET(SWIG_CXX_FLAGS)
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(WARNING_FLAGS
-Wno-unused-label
-Wno-unused-parameter
-Wno-unused-but-set-variable
-Wno-maybe-uninitialized
-Wno-uninitialized
-Wno-unused-value
)
FOREACH(COMPILER_FLAG ${WARNING_FLAGS})
# The ${COMPILER_FLAG} variable is cached, so the variable must be
# unique between flags.
check_cxx_compiler_flag("${COMPILER_FLAG}" RADIXSWIG_USE_FLAG_${COMPILER_FLAG})
IF(RADIXSWIG_USE_FLAG_${COMPILER_FLAG})
SET(SWIG_CXX_FLAGS "${SWIG_CXX_FLAGS} ${COMPILER_FLAG}")
ENDIF()
ENDFOREACH()
ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT WIN32)
SET(SWIG_CXX_FLAGS "${SWIG_CXX_FLAGS} -diag-disable 955")
ENDIF()
# Tell SWIG to use modern Python code
LIST(APPEND CMAKE_SWIG_FLAGS "-modern" "-noproxydel")
# If python version is high enough, add -py3 flag
IF(PYTHON_VERSION_STRING VERSION_GREATER 3.0)
LIST(APPEND CMAKE_SWIG_FLAGS "-py3")
ENDIF()
ENDIF()
##---------------------------------------------------------------------------##
# Look through a header/SWIG file and find dependencies
MACRO(get_swig_dependencies _RESULT_VAR _SOURCE)
# Search for dependencies in the SWIG file
FILE(STRINGS ${_SOURCE} HEADER_FILES
REGEX "^[ \t]*%include *\""
)
LIST(REMOVE_DUPLICATES HEADER_FILES)
# Set up test directories
SET(TEST_DIRS
${CMAKE_CURRENT_SOURCE_DIR}
${SCALE_SOURCE_DIR}/Exnihilo/packages
${SCALE_SOURCE_DIR}/packages
)
IF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/python")
LIST(APPEND TEST_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/python")
ENDIF()
# Get just the file names inside each "include"
SET(${_RESULT_VAR})
FOREACH(THEFILE ${HEADER_FILES})
STRING(REGEX REPLACE "^.*\"([^\"]+)\".*$" "\\1" THEFILE ${THEFILE})
IF( THEFILE )
FOREACH(TESTDIR ${TEST_DIRS})
IF(EXISTS ${TESTDIR}/${THEFILE})
LIST(APPEND ${_RESULT_VAR} ${TESTDIR}/${THEFILE})
BREAK()
ENDIF()
ENDFOREACH()
ENDIF()
ENDFOREACH()
ENDMACRO()
##---------------------------------------------------------------------------##
## ADDING SWIG MODULES
##---------------------------------------------------------------------------##
# RADIX_ADD_SWIG(
# MODULE module
# [SOURCE src.i]
# [DEPLIBS lib1 [lib2 ...]]
# [DEPMODULES module1 [module2 ...]]
# [EXTRASRC file1 [file2 ...]]
# )
#
# Create a SWIG-generated python module and shared object.
#
# The MODULE argument is the name of the resulting module file. By default it
# assumes the name "module.i", but that can be overriden with the SOURCE
# argument.
#
# All libraries in DEPLIBS will be linked against each target.
#
# Because TriBITS doesn't handle intra-SWIG module dependencies, we add a
# provision for extra dependency generation using the DEPMODULES list. For
# example, kba_utils will have "DEPMODULES denovo_utils ".
#
# The EXTRASRC argument allows additional sources to be compiled into the SWIG
# module target.
IF(ENABLE_PYTHON_WRAPPERS)
MACRO(RADIX_ADD_SWIG)
_RADIX_ADD_SWIG(${ARGN})
ENDMACRO()
# Bug fix: version of CMake older than 2.8.8 don't support the
# INCLUDE_DIRECTORIES property
IF(CMAKE_MAJOR_VERSION LESS 3
AND CMAKE_MINOR_VERSION LESS 9
AND CMAKE_PATCH_VERSION LESS 9)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
ELSE()
MACRO(RADIX_ADD_SWIG)
# no-op
MESSAGE(STATUS "Skipping python module setup for ${SUBPACKAGE_FULLNAME}")
ENDMACRO()
ENDIF()
##---------------------------------------------------------------------------##
FUNCTION(_RADIX_ADD_SWIG)
cmake_parse_arguments(MKSWIG "NO_ADD_OMPI" "MODULE;SOURCE"
"DEPLIBS;DEPMODULES;EXTRASRC" ${ARGN})
IF(NOT MKSWIG_MODULE)
MESSAGE(SEND_ERROR "Cannot call RADIX_ADD_SWIG without TARGET")
ENDIF()
SET(MODULE_NAME ${MKSWIG_MODULE})
IF(MKSWIG_SOURCE)
SET(SRC_FILE "${MKSWIG_SOURCE}")
ELSE()
SET(SRC_FILE "${MODULE_NAME}.i")
ENDIF()
# Let SWIG know that we're compiling C++ files
SET_SOURCE_FILES_PROPERTIES(${SRC_FILE} PROPERTIES CPLUSPLUS TRUE)
# Get dependencies of main SWIG source file and the files it includes
# we can't do recursive
SET(SUBDEPS ${SRC_FILE})
SET(DEPENDENCIES)
FOREACH(RECURSION 0 1 2)
SET(OLD_SUBDEPS ${SUBDEPS})
SET(SUBDEPS)
FOREACH(DEPENDENCY ${OLD_SUBDEPS})
IF(DEPENDENCY MATCHES "\\.i$")
get_swig_dependencies(SUBSUBDEPS ${DEPENDENCY})
LIST(APPEND SUBDEPS ${SUBSUBDEPS})
ENDIF()
ENDFOREACH()
LIST(APPEND DEPENDENCIES ${SUBDEPS})
ENDFOREACH()
SET(SWIG_MODULE_${MODULE_NAME}_EXTRA_DEPS ${DEPENDENCIES} )
# Add the new python target
IF("${CMAKE_VERSION}" VERSION_LESS "3.8.0")
SWIG_ADD_MODULE(${MODULE_NAME} python
${SRC_FILE} ${MKSWIG_EXTRASRC})
ELSE()
SWIG_ADD_LIBRARY(${MODULE_NAME}
LANGUAGE python
TYPE MODULE
SOURCES ${SRC_FILE} ${MKSWIG_EXTRASRC})
ENDIF()
# Mangled name of the SWIG target
SET(MKSWIG_TARGET ${SWIG_MODULE_${MODULE_NAME}_REAL_NAME})
# It's not always necessary to link against SWIG libraries, but doing so
# can turn unfortunate run-time errors (dlopen) into link-time errors.
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
IF(NOT ${PYTHON_LIBRARIES} MATCHES ".framework")
# Turn off undefined symbol errors on Mac systems where
# Python is not installed as a framework
# see http://bugs.python.org/issue1602133 about _initposix issues
SET_TARGET_PROPERTIES(${MKSWIG_TARGET}
PROPERTIES LINK_FLAGS "-undefined suppress -flat_namespace")
ELSE()
# Otherwise, link against Python libraries
SWIG_LINK_LIBRARIES(${MODULE_NAME} ${PYTHON_LIBRARIES})
ENDIF()
ENDIF()
# Link against other dependent libraries
SWIG_LINK_LIBRARIES(${MODULE_NAME} ${MKSWIG_DEPLIBS})
# Add intra-module dependencies
FOREACH(DEPMODULE ${MKSWIG_DEPMODULES})
ADD_DEPENDENCIES(${MKSWIG_TARGET} _${DEPMODULE})
ENDFOREACH()
# Include the Python directory and current source directory for the SWIG
# targets (SWIG processor and compilation of the resulting CXX file.) We don't
# use the INCLUDE_DIRECTORIES command because because TriBITS will
# propagate the path if we use INCLUDE_DIRECTORIES.
# Apply SWIG_CXX_FLAGS to hide warnings and such.
GET_TARGET_PROPERTY(INCL_DIR _${MODULE_NAME} INCLUDE_DIRECTORIES)
LIST(APPEND INCL_DIR ${PYTHON_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
LIST(REMOVE_DUPLICATES INCL_DIR)
SET_TARGET_PROPERTIES(_${MODULE_NAME} PROPERTIES
INCLUDE_DIRECTORIES "${INCL_DIR}"
COMPILE_FLAGS "${SWIG_CXX_FLAGS}")
# define the install targets
INSTALL(TARGETS ${MKSWIG_TARGET}
DESTINATION python)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}.py
DESTINATION python)
# clean up after SWIG (in cmake 2.6 - 2.8)
SET(swig_extra_generated_files)
ENDFUNCTION()
##---------------------------------------------------------------------------##
## end of RadixSWIGPyModules.cmake
##---------------------------------------------------------------------------##
......@@ -2,6 +2,7 @@ TRIBITS_SUBPACKAGE(io)
SET(SOURCE
arldatastream.cc
csvfile.cc
cfgfile.cc
eafstream.cc
......@@ -15,6 +16,7 @@ SET(SOURCE
)
SET(HEADERS
arldatastream.hh
csvfile.hh
cfgfile.hh
eafstream.hh
......@@ -40,6 +42,8 @@ TRIBITS_ADD_LIBRARY(radixio
#
# Add testing directory
TRIBITS_ADD_TEST_DIRECTORIES(tests)
# Add example directory
TRIBITS_ADD_EXAMPLE_DIRECTORIES(examples)
INSTALL(FILES ${HEADERS} DESTINATION "include/radixio/")
TRIBITS_SUBPACKAGE_POSTPROCESS()
#include "radixio/arldatastream.hh"
#include "radixbug/bug.hh"
#include "radixcore/stringfunctions.hh"
#include "radixio/eafstream.hh"
#include "radixmath/util.hh"
#include <fstream>
namespace radix
{
class ARLDataStream::PImpl
{
public:
std::string file;
std::shared_ptr<radix::eafstream> stream;
int recordSize = 0;
static const int recordHeaderLength = 50, indexHeaderLength = 108;
};
void ARLDataStream::expand(const std::string& val, ARLRecordHeader& rheader)
{
if (val.size() < ARLDataStream::PImpl::recordHeaderLength)
{
throw std::runtime_error(
"Incorrect size for string expansion to ARLRecordHeader.");
}
rheader.year = std::atoi(val.substr(0, 2).c_str());
rheader.month = std::atoi(val.substr(2, 2).c_str());
rheader.day = std::atoi(val.substr(4, 2).c_str());
rheader.hour = std::atoi(val.substr(6, 2).c_str());
rheader.ic = std::atoi(val.substr(8, 2).c_str());
rheader.il = std::atoi(val.substr(10, 2).c_str());
rheader.cgrid = val.substr(12, 2).c_str();
rheader.kvar = val.substr(14, 4);
rheader.nexp = std::atoi(val.substr(18, 4).c_str());
rheader.prec = float(std::atof(val.substr(22, 14).c_str()));
rheader.var1 = float(std::atof(val.substr(36, 14).c_str()));
}
void ARLDataStream::expand(const std::string& val,
const ARLRecordHeader& rheader,
ARLIndexHeader& iheader)
{
if (val.size() < ARLDataStream::PImpl::indexHeaderLength)
{
throw std::runtime_error(
"Incorrect size for string expansion to ARLHeader.");
}
iheader.model_id = val.substr(0, 4);
iheader.icx = std::atoi(val.substr(4, 3).c_str());
iheader.mn = std::atoi(val.substr(7, 2).c_str());
iheader.pole_lat = float(std::atof(val.substr(9, 7).c_str()));
iheader.pole_lon = float(std::atof(val.substr(16, 7).c_str()));
iheader.ref_lat = float(std::atof(val.substr(23, 7).c_str()));
iheader.ref_lon = float(std::atof(val.substr(30, 7).c_str()));
iheader.size = float(std::atof(val.substr(37, 7).c_str()));
iheader.orient = float(std::atof(val.substr(44, 7).c_str()));
iheader.tang_lat = float(std::atof(val.substr(51, 7).c_str()));
iheader.sync_xp = float(std::atof(val.substr(58, 7).c_str()));
iheader.sync_yp = float(std::atof(val.substr(65, 7).c_str()));
iheader.sync_lat = float(std::atof(val.substr(72, 7).c_str()));
iheader.sync_lon = float(std::atof(val.substr(79, 7).c_str()));
iheader.dummy = float(std::atof(val.substr(86, 7).c_str()));
iheader.nx = std::atoi(val.substr(93, 3).c_str());
iheader.ny = std::atoi(val.substr(96, 3).c_str());
iheader.nz = std::atoi(val.substr(99, 3).c_str());
iheader.z_flag = std::atoi(val.substr(102, 2).c_str());
iheader.lenh = std::atoi(val.substr(104, 4).c_str());
int knx = ordinal(rheader.cgrid[0]);
int kny = ordinal(rheader.cgrid[1]);
// Check for the grid domain extending beyond 3 digits
if (knx >= 64 || kny >= 64)
{
iheader.nx = (knx - 64) * 1000 + iheader.nx;
iheader.ny = (kny - 64) * 1000 + iheader.ny;
}
}
ARLDataStream::ARLDataStream(const std::string& file,
std::ios_base::openmode mode)
: p(new PImpl(), [](PImpl* impl) { delete impl; })
{
p->file = file;
p->stream = std::make_shared<radix::eafstream>(p->file.c_str(),
mode | std::ios::binary);
if (!p->stream->is_open())
{
throw std::runtime_error("Error opening file '" + p->file + "'");
}
}
bool ARLDataStream::read_record_header(ARLRecordHeader& rheader)
{
bool result = false;
std::string headerString =
p->stream->readString(ARLDataStream::PImpl::recordHeaderLength);
expand(headerString, rheader);
radix_line("Read record header: year = " << rheader.year);
radix_line(" month = " << rheader.month);
radix_line(" day = " << rheader.day);
radix_line(" hour = " << rheader.hour);
radix_line(" variable = " << rheader.kvar);
radix_line(" scaling exponent = " << rheader.nexp);
radix_line(" initial value = " << rheader.var1);
radix_line(" header as string:\n " << headerString);
result = true;
return result;
}
bool ARLDataStream::write_record_header(const ARLRecordHeader& rheader)
{
bool result = false;
// Remove century from year
int year = rheader.year % 100;
radix_line("Write record header: year = " << year);
radix_line(" month = " << rheader.month);
radix_line(" day = " << rheader.day);
radix_line(" hour = " << rheader.hour);
radix_line(" variable = " << rheader.kvar);
radix_line(" level = " << rheader.il);
radix_line(" scaling exponent = " << rheader.nexp);
radix_line(" initial value = " << rheader.var1);
// Construct index header string
char recordHeader[50];
sprintf(recordHeader, "%2d%2d%2d%2d%2d%2d%2d%4s%4d%14.7E%14.7E", year,
rheader.month, rheader.day, rheader.hour, rheader.ic, rheader.il,
std::stoi(rheader.cgrid.c_str()), rheader.kvar.c_str(), rheader.nexp,
rheader.prec, rheader.var1);
p->stream->writeString(std::string(recordHeader),
ARLDataStream::PImpl::recordHeaderLength);
radix_line(" header as string:\n " << recordHeader);
result = true;
return result;
}
bool ARLDataStream::read_next_record_header(ARLRecordHeader& rheader)
{
int bytesToSkip = roundUpInt(p->stream->bytesRead(), p->recordSize) -
p->stream->bytesRead();
radix_line("Skipping " << bytesToSkip << " bytes to the next record header");
p->stream->skipBytes(bytesToSkip);
return read_record_header(rheader);
}
bool ARLDataStream::read_index_header(const ARLRecordHeader& rheader,
ARLIndexHeader& iheader)
{
bool result = false;
// Read main part of index header
radix_line(" Reading main part of index header...");
std::string headerString =
p->stream->readString(ARLDataStream::PImpl::indexHeaderLength);
expand(headerString, rheader, iheader);
// Calculate and save record size
p->recordSize =
(iheader.nx * iheader.ny) + ARLDataStream::PImpl::recordHeaderLength;
// Read variable description part of index header
radix_line(" Reading variable part of index header... " << iheader.nz
<< " levels");
for (size_t level = 0; level < size_t(iheader.nz); ++level)
{
// Read levels information
std::string levelString = p->stream->readString(6);
iheader.levels.push_back(std::stof(levelString));
std::string nVarsString = p->stream->readString(2);
iheader.num_vars_at_levels.push_back(std::stoi(nVarsString));
// Read names and checksums
iheader.var_names.push_back(std::vector<std::string>());
iheader.check_sums.push_back(std::vector<int>());
radix_line(" Level " << level << "... "
<< iheader.num_vars_at_levels[level] << " vars");
for (int var = 0; var < iheader.num_vars_at_levels[level]; ++var)
{
std::string nameString = p->stream->readString(4);
iheader.var_names[level].push_back(nameString);
std::string sumString = p->stream->readString(3);
iheader.check_sums[level].push_back(std::stoi(sumString));
p->stream->skipBytes(1);
}
}
radix_line(" Read index header: model = " << iheader.model_id);
radix_line(" nx = " << iheader.nx);
radix_line(" ny = " << iheader.ny);
radix_line(" nz = " << iheader.nz);
radix_line(" Size of each record = " << p->recordSize);
radix_line(" header as string:\n " << headerString);
result = true;
return result;
}
bool ARLDataStream::write_index_header(const ARLRecordHeader& rheader,
const ARLIndexHeader& iheader)
{
bool result = false;
// Calculate and save record size
p->recordSize =
(iheader.nx * iheader.ny) + ARLDataStream::PImpl::recordHeaderLength;
radix_line(" Write index header: model = " << iheader.model_id);
radix_line(" nx = " << iheader.nx);
radix_line(" ny = " << iheader.ny);
radix_line(" nz = " << iheader.nz);
radix_line(" Size of each record = " << p->recordSize);
const size_t MAX_HEADER_LENGTH = 10000;
char indexHeaderMain[ARLDataStream::PImpl::indexHeaderLength],
indexHeaderVars[MAX_HEADER_LENGTH];
int pos = 0;
// Write the variable description part of the header
for (size_t level = 0; level < size_t(iheader.nz); ++level)
{
pos += sprintf(indexHeaderVars + pos, "%6.1f", iheader.levels[level]);
pos += sprintf(indexHeaderVars + pos, "%2d",
iheader.num_vars_at_levels[level]);
for (size_t var = 0; var < size_t(iheader.num_vars_at_levels[level]); ++var)
{
pos += sprintf(indexHeaderVars + pos, "%4s",
iheader.var_names[level][var].c_str());
pos += sprintf(indexHeaderVars + pos, "%3d ",
iheader.check_sums[level][var]);
}
}
// Construct the main part of the header (inc. size calculation)
int headerLength = ARLDataStream::PImpl::indexHeaderLength + pos;
sprintf(indexHeaderMain,
"%4s%3d%2d%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f%7.2f%7."
"2f%3d%3d%3d%2d%4d",
iheader.model_id.c_str(), iheader.icx, iheader.mn, iheader.pole_lat,
iheader.pole_lon, iheader.ref_lat, iheader.ref_lon, iheader.size,
iheader.orient, iheader.tang_lat, iheader.sync_xp, iheader.sync_yp,
iheader.sync_lat, iheader.sync_lon, iheader.dummy, iheader.nx,
iheader.ny, iheader.nz, iheader.z_flag, headerLength);
// Write the two elements of the header
p->stream->writeString(std::string(indexHeaderMain),
ARLDataStream::PImpl::indexHeaderLength);